def main(): # noinspection PyTypeChecker parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument("--bitfile", help="The bitfile to load", type=abspath_arg) parser.add_argument("--ltxfile", help="The LTX file to use", type=abspath_arg) parser.add_argument("--bios", help="The machine-mode program to load", type=abspath_arg) parser.add_argument("--kernel", help="The supervisor-mode program to load", type=abspath_arg) parser.add_argument("--kernel-debug-file", help="Debug info file for the kernel", type=abspath_arg) parser.add_argument("--gdb", default=shutil.which("gdb") or "gdb", help="Path to GDB binary", type=Path) parser.add_argument("--openocd", default=shutil.which("openocd") or "openocd", help="Path to openocd binary", type=abspath_arg) parser.add_argument("--num-cores", type=int, default=1, help="Number of harts on bitstream") parser.add_argument("--test-command", action='append', help="Run a command non-interactively before possibly opening a console") parser.add_argument("--test-timeout", type=int, default=60 * 60, help="Timeout for the test command") parser.add_argument("--pretend", help="Don't actually run the commands just show what would happen", action="store_true") parser.add_argument("action", choices=["all", "bitfile", "boot", "console"], default="all", nargs=argparse.OPTIONAL) try: # noinspection PyUnresolvedReferences import argcomplete argcomplete.autocomplete(parser) except ImportError: pass args = parser.parse_args() print(args) init_global_config(ConfigBase(pretend=args.pretend, verbose=True, quiet=False)) if (args.action == "all" and args.bitfile is not None) or args.action == "bitfile": if args.ltxfile is None: args.ltxfile = Path(args.bitfile).with_suffix(".ltx") load_bitfile(args.bitfile, args.ltxfile, FileSystemUtils(get_global_config())) if args.action == "bitfile": sys.exit(0) tty_info = find_vcu118_tty(args.pretend) success("Found TTY:", tty_info) info(tty_info.usb_info()) if args.action == "console": console = get_console(tty_info) console.interact() return else: conn = load_and_start_kernel(gdb_cmd=args.gdb, openocd_cmd=args.openocd, bios_image=args.bios, kernel_image=args.kernel, kernel_debug_file=args.kernel_debug_file, tty_info=tty_info, num_cores=args.num_cores) console = conn.serial if args.action == "boot": sys.exit(0) if args.test_command is not None: success("Running test commands") for test_command in args.test_command: console.cheribsd.checked_run(test_command, timeout=args.test_timeout) # Finally interact with the console (if possible) if not sys.__stdin__.isatty(): success("Not interating with console since stdin is not a TTY. Exiting now.") else: console.interact()
def __init__(self, executable, args): if get_global_config().pretend: self.cheribsd = FakeSerialSpawn(executable, args) else: print_command([executable, *args]) self.cheribsd = CheriBSDInstance(CompilationTargets.CHERIBSD_RISCV_HYBRID, executable, args, logfile=sys.stdout, encoding="utf-8", timeout=60) assert isinstance(self.cheribsd, CheriBSDSpawnMixin)
def load_bitfile(bitfile: Path, ltxfile: Path, fu: FileSystemUtils): if shutil.which("vivado") is None: fatal_error("vivado not in $PATH, cannot continue") if bitfile is None or not bitfile.exists(): fatal_error("Missing bitfile:", bitfile) if ltxfile is None or not ltxfile.exists(): fatal_error("Missing ltx file:", ltxfile) with tempfile.NamedTemporaryFile() as t: t.write(VIVADO_SCRIPT) t.flush() args = [ "vivado", "-nojournal", "-notrace", "-nolog", "-source", t.name, "-mode", "batch", "-tclargs", str(bitfile), str(ltxfile) ] print_command(args, config=get_global_config()) if get_global_config().pretend: vivado = PretendSpawn(args[0], args[1:]) else: vivado = pexpect.spawn(args[0], args[1:], logfile=sys.stdout, encoding="utf-8") vivado_exit_str = "Exiting Vivado at" if vivado.expect_exact(["****** Vivado", vivado_exit_str]) != 0: failure("Vivado failed to start", exit=True) success("Vivado started") if vivado.expect_exact(["Programming...", vivado_exit_str]) != 0: failure("Vivado failed to start programming", exit=True) success("Vivado started programming FPGA") # 5 minutes should be enough time to programt the FPGA if vivado.expect_exact(["Done!", vivado_exit_str], timeout=5 * 60) != 0: failure("Vivado failed to program FPGA", exit=True) success("Vivado finished programming FPGA") vivado.expect_exact([vivado_exit_str]) vivado.wait() fu.delete_file(Path("webtalk.log"), print_verbose_only=True) fu.delete_file(Path("webtalk.jou"), print_verbose_only=True) if not get_global_config().pretend: # wait for 3 seconds to avoid 'Error: libusb_claim_interface() failed with LIBUSB_ERROR_BUSY' time.sleep(3)
def start_openocd(openocd_cmd: Path, num_cores: int) -> typing.Tuple[pexpect.spawn, int]: with tempfile.NamedTemporaryFile() as t: t.write(generate_openocd_script(num_cores)) t.flush() cmdline = [str(openocd_cmd), "-f", t.name] print_command(cmdline, config=get_global_config()) if get_global_config().pretend: openocd = PretendSpawn(cmdline[0], cmdline[1:]) else: openocd = pexpect.spawn(cmdline[0], cmdline[1:], logfile=sys.stdout, encoding="utf-8") openocd.expect_exact(["Open On-Chip Debugger"]) success("openocd started") gdb_port = 3333 openocd.expect(["Info : Listening on port (\\d+) for gdb connections"]) if openocd.match is not None: gdb_port = int(openocd.match.group(1)) openocd.expect_exact(["Info : Listening on port 4444 for telnet connections"]) success("openocd waiting for GDB connection") return openocd, gdb_port
def load_and_start_kernel(*, gdb_cmd: Path, openocd_cmd: Path, bios_image: Path, kernel_image: Path = None, kernel_debug_file: Path = None, tty_info: ListPortInfo, num_cores: int) -> FpgaConnection: # Open the serial connection first to check that it's available: serial_conn = get_console(tty_info) success("Connected to TTY") if bios_image is None or not bios_image.exists(): failure("Missing bios image: ", bios_image) # First start openocd gdb_start_time = datetime.datetime.utcnow() openocd, openocd_gdb_port = start_openocd(openocd_cmd, num_cores) # openocd is running, now start GDB args = [ str(Path(bios_image).absolute()), "-ex", "target extended-remote :" + str(openocd_gdb_port) ] args += ["-ex", "set confirm off"] # avoid interactive prompts args += ["-ex", "set pagination off"] # avoid paginating output, requiring input args += ["-ex", "set style enabled off" ] # disable colours since they break the matcher strings args += ["-ex", "monitor reset init"] # reset and go back to boot room args += ["-ex", "si 5" ] # we need to run the first few instructions to get a valid DTB args += ["-ex", "set disassemble-next-line on"] # Load the kernel image first since load changes the next PC to the entry point if kernel_image is not None: kernel_image = kernel_image.absolute() if kernel_debug_file is None: # If there is a .full image use that to get debug symbols: full_file = kernel_image.with_name(kernel_image.name + ".full") if full_file.exists(): kernel_debug_file = full_file else: # Fall back to the kernel image without debug info. kernel_debug_file = kernel_image args += [ "-ex", "symbol-file " + shlex.quote(str(kernel_debug_file.absolute())) ] args += ["-ex", "load " + shlex.quote(str(kernel_image.absolute()))] args += ["-ex", "load " + shlex.quote(str(Path(bios_image).absolute()))] if num_cores > 1: args += ["-ex", "set $entry_point = $pc" ] # Record the entry point to the bios for core in range(1, num_cores): args += ["-ex", "thread {:d}".format(core + 1) ] # switch to thread (core + 1) (GDB counts from 1) args += ["-ex", "si 5"] # execute bootrom on every other core args += ["-ex", "set $pc=$entry_point" ] # set every other core to the start of the bios args += ["-ex", "thread 1"] # switch back to core 0 print_command(str(gdb_cmd), *args, config=get_global_config()) if get_global_config().pretend: gdb = PretendSpawn(str(gdb_cmd), args, timeout=60) else: gdb = pexpect.spawn(str(gdb_cmd), args, timeout=60, logfile=sys.stdout, encoding="utf-8") gdb.expect_exact(["Reading symbols from"]) # openOCD should acknowledge the GDB connection: openocd.expect_exact([ "Info : accepting 'gdb' connection on tcp/{}".format(openocd_gdb_port) ]) success("openocd accepted GDB connection") gdb.expect_exact(["Remote debugging using :" + str(openocd_gdb_port)]) success("GDB connected to openocd") # XXX: doesn't match with recent GDB: gdb.expect_exact(["0x0000000070000000 in ??"]) gdb.expect_exact(["0x0000000070000000"]) success("PC set to bootrom") # XXX: doesn't match with recent GDB: gdb.expect_exact(["0x0000000044000000 in ??"]) gdb.expect_exact(["0x0000000044000000"]) success("Done executing bootrom") if kernel_image is not None: gdb.expect_exact(["Loading section .text"]) load_start_time = datetime.datetime.utcnow() success("Started loading kernel image (this may take a long time)") gdb.expect_exact(["Transfer rate:"], timeout=120 * 60) # XXX: is 2 hours a sensible timeout? load_end_time = datetime.datetime.utcnow() success("Finished loading kernel image in ", load_end_time - load_start_time) # Now load the bootloader gdb.expect_exact(["Loading section .text"]) load_start_time = datetime.datetime.utcnow() success("Started loading bootloader image") gdb.expect_exact(["Transfer rate:"], timeout=10 * 60) # XXX: is 10 minutes a sensible timeout? load_end_time = datetime.datetime.utcnow() success("Finished loading bootloader image in ", load_end_time - load_start_time) gdb_finish_time = load_end_time if num_cores > 1: for core in range(1, num_cores): gdb.expect_exact(["0x0000000044000000"]) success("Done executing bootrom on all other cores") gdb.sendline("continue") success("Starting CheriBSD after ", datetime.datetime.utcnow() - gdb_start_time) i = serial_conn.cheribsd.expect_exact( ["bbl loader", "---<<BOOT>>---", pexpect.TIMEOUT], timeout=30) if i == 0: success("bbl loader started") elif i == 1: success("FreeBSD boot started") else: failure("Did not get expected boot output", exit=True) # TODO: network_iface="xae0", but DHCP doesn't work boot_and_login(serial_conn.cheribsd, starttime=gdb_finish_time, network_iface=None) return FpgaConnection(gdb, openocd, serial_conn)
def main(): # noinspection PyTypeChecker parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument("--bitfile", help="The bitfile to load", type=abspath_arg) parser.add_argument("--ltxfile", help="The LTX file to use", type=abspath_arg) parser.add_argument("--bios", default="openocd", help="The machine-mode program to load", type=abspath_arg) parser.add_argument("--kernel", help="The supervisor-mode program to load", type=abspath_arg) parser.add_argument("--kernel-debug-file", help="Debug info file for the kernel", type=abspath_arg) parser.add_argument("--gdb", default=shutil.which("gdb") or "gdb", help="Path to GDB binary", type=Path) parser.add_argument("--openocd", default=shutil.which("openocd") or "openocd", help="Path to openocd binary", type=abspath_arg) parser.add_argument( "--pretend", help="Don't actually run the commands just show what would happen", action="store_true") parser.add_argument("action", choices=["all", "bitfile", "boot", "console"], default="all", nargs=argparse.OPTIONAL) try: # noinspection PyUnresolvedReferences import argcomplete argcomplete.autocomplete(parser) except ImportError: pass args = parser.parse_args() print(args) init_global_config( ConfigBase(pretend=args.pretend, verbose=True, quiet=False)) if (args.action == "all" and args.bitfile is not None) or args.action == "bitfile": if args.ltxfile is None: args.ltxfile = Path(args.bitfile).with_suffix(".ltx") load_bitfile(args.bitfile, args.ltxfile, FileSystemUtils(get_global_config())) if args.action == "bitfile": sys.exit(0) tty_info = find_vcu118_tty() success("Found TTY:", tty_info) info(tty_info.usb_info()) if args.action == "console": console = get_console(tty_info) else: conn = load_and_start_kernel(gdb_cmd=args.gdb, openocd_cmd=args.openocd, bios_image=args.bios, kernel_image=args.kernel, kernel_debug_file=args.kernel_debug_file, tty_info=tty_info) console = conn.serial if args.action == "boot": sys.exit(0) # interact() prints all input+output -> disable logfile console.cheribsd.logfile = None console.cheribsd.logfile_read = None console.cheribsd.logfile_send = None console.show_help_message() if args.action == "console": pass # TODO? console.sendintr() # Send CTRL+C to get a clean prompt console.cheribsd.interact()