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 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)