xref: /openbmc/openbmc/meta-arm/scripts/runfvp (revision ac13d5f36a6bd845f1709b7f41c02bd3b412ad15)
1bec4ebc2SBrad Bishop#! /usr/bin/env python3
2bec4ebc2SBrad Bishop
37784c429SPatrick Williamsimport itertools
4bec4ebc2SBrad Bishopimport os
5bec4ebc2SBrad Bishopimport pathlib
6bec4ebc2SBrad Bishopimport signal
7bec4ebc2SBrad Bishopimport sys
87784c429SPatrick Williamsimport threading
9bec4ebc2SBrad Bishop
10bec4ebc2SBrad Bishopimport logging
11bec4ebc2SBrad Bishoplogger = logging.getLogger("RunFVP")
12bec4ebc2SBrad Bishop
13bec4ebc2SBrad Bishop# Add meta-arm/lib/ to path
14bec4ebc2SBrad Bishoplibdir = pathlib.Path(__file__).parents[1] / "meta-arm" / "lib"
15bec4ebc2SBrad Bishopsys.path.insert(0, str(libdir))
16bec4ebc2SBrad Bishop
1723e02799SAndrew Geisslerfrom fvp import conffile, terminal, runner
18bec4ebc2SBrad Bishop
19bec4ebc2SBrad Bishopdef parse_args(arguments):
20bec4ebc2SBrad Bishop    import argparse
21bec4ebc2SBrad Bishop    terminals = terminal.terminals
22bec4ebc2SBrad Bishop
23bec4ebc2SBrad Bishop    parser = argparse.ArgumentParser(description="Run images in a FVP")
24bec4ebc2SBrad Bishop    parser.add_argument("config", nargs="?", help="Machine name or path to .fvpconf file")
25bec4ebc2SBrad Bishop    group = parser.add_mutually_exclusive_group()
26bec4ebc2SBrad Bishop    group.add_argument("-t", "--terminals", choices=terminals.all_terminals(), default=terminals.preferred_terminal(), help="Automatically start terminals (default: %(default)s)")
27bec4ebc2SBrad Bishop    group.add_argument("-c", "--console", action="store_true", help="Attach the first uart to stdin/stdout")
28bec4ebc2SBrad Bishop    parser.add_argument("--verbose", action="store_true", help="Output verbose logging")
29bec4ebc2SBrad Bishop    parser.usage = f"{parser.format_usage().strip()} -- [ arguments passed to FVP ]"
30bec4ebc2SBrad Bishop    # TODO option for telnet vs netcat
31bec4ebc2SBrad Bishop
32bec4ebc2SBrad Bishop    # If the arguments contains -- then everything after it should be passed to the FVP binary directly.
33bec4ebc2SBrad Bishop    if "--" in arguments:
34bec4ebc2SBrad Bishop        i = arguments.index("--")
35bec4ebc2SBrad Bishop        fvp_args = arguments[i+1:]
36bec4ebc2SBrad Bishop        arguments = arguments[:i]
37bec4ebc2SBrad Bishop    else:
38bec4ebc2SBrad Bishop        fvp_args = []
39bec4ebc2SBrad Bishop
40bec4ebc2SBrad Bishop    args = parser.parse_args(args=arguments)
417784c429SPatrick Williams    logging.basicConfig(level=args.verbose and logging.DEBUG or logging.WARNING,
427784c429SPatrick Williams                        format='\033[G%(levelname)s: %(message)s')
43bec4ebc2SBrad Bishop
44bec4ebc2SBrad Bishop    # If we're hooking up the console, don't start any terminals
45bec4ebc2SBrad Bishop    if args.console:
46bec4ebc2SBrad Bishop        args.terminals = "none"
47bec4ebc2SBrad Bishop
48bec4ebc2SBrad Bishop    logger.debug(f"Parsed arguments: {vars(args)}")
49bec4ebc2SBrad Bishop    logger.debug(f"FVP arguments: {fvp_args}")
50bec4ebc2SBrad Bishop    return args, fvp_args
51bec4ebc2SBrad Bishop
52e760df85SPatrick Williamsdef start_fvp(args, fvpconf, extra_args):
53bec4ebc2SBrad Bishop    fvp = runner.FVPRunner(logger)
54bec4ebc2SBrad Bishop    try:
55e760df85SPatrick Williams        fvp.start(fvpconf, extra_args, args.terminals)
56bec4ebc2SBrad Bishop
57bec4ebc2SBrad Bishop        if args.console:
58e760df85SPatrick Williams            config = fvp.getConfig()
59e760df85SPatrick Williams            expected_terminal = config["consoles"].get("default")
60e760df85SPatrick Williams            if expected_terminal is None:
61bec4ebc2SBrad Bishop                logger.error("--console used but FVP_CONSOLE not set in machine configuration")
62bec4ebc2SBrad Bishop                return 1
637784c429SPatrick Williams            port_stdout, log_stdout = itertools.tee(fvp.stdout, 2)
647784c429SPatrick Williams            parser = runner.ConsolePortParser(port_stdout)
657784c429SPatrick Williams            port = parser.parse_port(expected_terminal)
667784c429SPatrick Williams
677784c429SPatrick Williams            def debug_log():
687784c429SPatrick Williams                for line in log_stdout:
697784c429SPatrick Williams                    line = line.strip().decode(errors='ignore')
707784c429SPatrick Williams                    logger.debug(f'FVP output: {line}')
717784c429SPatrick Williams            log_thread = threading.Thread(None, debug_log)
727784c429SPatrick Williams            log_thread.start()
737784c429SPatrick Williams
747784c429SPatrick Williams            telnet = fvp.create_telnet(port)
757784c429SPatrick Williams            telnet.wait()
76bec4ebc2SBrad Bishop            logger.debug(f"Telnet quit, cancelling tasks")
77bec4ebc2SBrad Bishop        else:
787784c429SPatrick Williams            for line in fvp.stdout:
797784c429SPatrick Williams                print(line.strip().decode(errors='ignore'))
80db4c27eeSPatrick Williams
81bec4ebc2SBrad Bishop    finally:
82*ac13d5f3SPatrick Williams        return fvp.stop()
837784c429SPatrick Williams
84bec4ebc2SBrad Bishop
85bec4ebc2SBrad Bishopdef runfvp(cli_args):
86bec4ebc2SBrad Bishop    args, extra_args = parse_args(cli_args)
87bec4ebc2SBrad Bishop    if args.config and pathlib.Path(args.config).exists():
88bec4ebc2SBrad Bishop        config_file = args.config
89bec4ebc2SBrad Bishop    else:
90bec4ebc2SBrad Bishop        config_file = conffile.find(args.config)
91*ac13d5f3SPatrick Williams    return start_fvp(args, config_file, extra_args)
92bec4ebc2SBrad Bishop
93bec4ebc2SBrad Bishop
94bec4ebc2SBrad Bishopif __name__ == "__main__":
95bec4ebc2SBrad Bishop    try:
96bec4ebc2SBrad Bishop        # Set the process group so that it's possible to kill runfvp and
97bec4ebc2SBrad Bishop        # everything it spawns easily.
98bec4ebc2SBrad Bishop        # Ignore permission errors happening when spawned from an other process
99bec4ebc2SBrad Bishop        # for example run from except
100bec4ebc2SBrad Bishop        try:
101bec4ebc2SBrad Bishop            os.setpgid(0, 0)
102bec4ebc2SBrad Bishop        except PermissionError:
103bec4ebc2SBrad Bishop            pass
104bec4ebc2SBrad Bishop        if sys.stdin.isatty():
105bec4ebc2SBrad Bishop            signal.signal(signal.SIGTTOU, signal.SIG_IGN)
106bec4ebc2SBrad Bishop            os.tcsetpgrp(sys.stdin.fileno(), os.getpgrp())
107bec4ebc2SBrad Bishop        sys.exit(runfvp(sys.argv[1:]))
108bec4ebc2SBrad Bishop    except KeyboardInterrupt:
109bec4ebc2SBrad Bishop        pass
110