Zynq 7000. Загрузка Embedded Linux на SoC через JTAG с помощью XSCT
Учитывая, что я очень давно занимаюсь отладкой и запуском самых разнообразных проектов связанных с Zynq 7000 — со временем количество итераций перезапуска при проведении отладки увеличивалось пропорционально сложности проекта. Когда я только начинал осваивать разработку под Zynq, то каждый раз закидывал новый образ на microSD карту. Это было очень медленным процессом и требовало от меня постоянно подключать/отключать карту. После этого я освоил сетевую загрузку через Ethernet и TFTP, заменяя файлы по сети и проверяя результат после перезагрузки.
Впоследствии, изучив вопрос связанный с типами загрузки, я обнаружил, что есть альтернативный способ загрузки платы через интерфейс JTAG, который впрочем может оказаться единственным доступным, если на плате нет microSD и Ethernet.
Вот как раз вопросы связанные с тем, как произвести загрузку по JTAG я бы хотел осветить в этой статье. Всем кому интересно — добро пожаловать под кат.
❯ Дисклеймер
Перед началом повествования хотелось бы заранее оговориться, что основная цель, которую я преследую при написании этой статьи — рассказать о своем опыте, с чего можно начать, при изучении отладочных плат на базе Zynq. Я не являюсь профессиональным разработчиком под ПЛИС и SoC Zynq, не являюсь системным программистом под Linux и могу допускать какие-либо ошибки в использовании терминологии, использовать не самые оптимальные пути решения задач, etc. Но отмечу, что любая конструктивная и аргументированная критика только приветствуется.
❯ Что такое сервер XSCT?
В составе набора инструментов для работы Zynq 700 имеется утилита XSCT т. е. Xilinx Software Command-line Tool. По сути — это командная строка, которая поддерживает выполнение скриптов в режиме интерактивного терминала. Данная тулза предоставляет огромное количество самых разных возможностей, большую часть которых мы не будем рассматривать в рамках данной статьи. Всем интересующимся — в документ UG-1400.
Мы лишь ограничимся рассмотрением опций загрузки устройства через JTAG.
❯ Что необходимо из аппаратного обеспечения?
Так как в этой статье я буду рассматривать выполнения загрузки на Zynq Mini — на нем уже имеется встроенный отладчик JTAG и никаких внешних устройств не потребуется. В случае, если вы выполняете действия на какой-то другой железке — вам обязательно понадобится стандартный отладчик JTAG от Xilinx и плата должна иметь выводы JTAG. Выглядит он следующим образом:
Либо есть альтернативный вариант для отладки, который дает возможность проводить отладку в т. ч. по сети Ethernet. Называется эта железка Xilinx SmartLynq JTAG Cable:
Но стоит данная железка не мало, в районе 130К рублей и рассматривать мы ее не будем. Большая часть доступных отладчиков для Zynq отличается между собой используемым чипом и есть медленные варианты, но есть отладчики на чипах FTDI, которые обеспечивают высокую скорость загрузки образов.
❯ Загрузка с помощью JTAG по шагам
Ниже я рассмотрю набор шагов, которые позволят осуществить задуманное. Постарайтесь сначала выполнить все шаги, четко разобрав всё в деталях. Следуя описанию шагов, вы поймете, за что отвечает каждое действие и в последующем уже сможете адаптировать мануал для себя, и возможно даже напишете скрипт для быстрой загрузки собранных артефактов сразу в плату одной командой.
❯ Запуск сервера XSCT
В первую очередь необходимо запустить сервер XSCT из директории, в которой установлен Xilinx Vivado/Vitis. Обычно он находится в директории Xilinx/Vitis/2021.1/bin/xsct. После запуска утилиты появляется командная строка. С этой утилитой можно взаимодействовать в т. ч. с помощью специальных TCL-скриптов.
megalloid@megalloid-xubuntu:~$ cd Xilinx/Vitis/2023.2/bin/
megalloid@megalloid-xubuntu:~/Xilinx/Vitis/2023.2/bin$ ./xsct
Display is :185
rlwrap: warning: your $TERM is 'xterm-256color' but rlwrap couldn't find it in the terminfo database. Expect some problems.
7
****** Software Commandline Tool (XSCT) v2023.2.2
**** SW Build 0 on 2024-02-08-22:35:25
** Copyright 1986-2022 Xilinx, Inc. All Rights Reserved.
** Copyright 2022-2024 Advanced Micro Devices, Inc. All Rights Reserved.
Note: XSCT has been deprecated. It will still be available for several releases.It's recommended to start new projects with new python command line tool.
Use "vitis -s <script>" (script mode) and "vitis -i" (interactive mode) to load new Python CLI for Vitis.
xsct% help
Available Help Categories
breakpoints - Target Breakpoints/Watchpoints.
connections - Target Connection Management.
device - Device Configuration System.
download - Target Download FPGA/BINARY.
hsi - HSI commands.
ipi - IPI commands to Versal PMC.
jtag - JTAG Access.
memory - Target Memory.
miscellaneous - Miscellaneous.
petalinux - Petalinux commands.
projects - Vitis Projects.
registers - Target Registers.
reset - Target Reset.
running - Program Execution.
sdtgen - System Device Tree.
stapl - STAPL Operations.
streams - Jtag UART.
svf - SVF Operations.
tfile - Target File System.
Type "help" followed by above "category" for more details or
help" followed by the keyword "commands" to list all the commands
xsct%
❯ Установка драйверов и решение проблемы отсутствия устройства в списке
Проверим, детектируется ли отладчик в списке доступных устройств:
xsct% connect
attempting to launch hw_server
****** Xilinx hw_server v2023.2.2
**** Build date : Jan 5 2024 at 11:23:30
** Copyright 1986-2022 Xilinx, Inc. All Rights Reserved.
** Copyright 2022-2024 Advanced Micro Devices, Inc. All Rights Reserved.
INFO: hw_server application started
INFO: Use Ctrl-C to exit hw_server application
INFO: To connect to this hw_server instance use url: TCP:127.0.0.1:3121
tcfchan#0
xsct% targets
xsct%
В списке ничего нет. Вытыкаем устройство из ПК и подключаем обратно, смотрим dmesg:
[ 1901.337966] usb 1-5: new high-speed USB device number 6 using xhci_hcd
[ 1901.491022] usb 1-5: New USB device found, idVendor=0403, idProduct=6014, bcdDevice= 9.00
[ 1901.491038] usb 1-5: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 1901.491046] usb 1-5: Product: Digilent USB Device
[ 1901.491052] usb 1-5: Manufacturer: Digilent
[ 1901.491058] usb 1-5: SerialNumber: 210251A08870
[ 1901.495113] ftdi_sio 1-5:1.0: FTDI USB Serial Device converter detected
[ 1901.495205] usb 1-5: Detected FT232H
[ 1901.496522] usb 1-5: FTDI USB Serial Device converter now attached to ttyUSB0
Скорее всего устройство просто не имеет udev-правила, которое определяет конфигурацию для вновь подключенного устройства. Добавим его.
Для этого нужно сделать следующее:
megalloid@megalloid-xubuntu:~$ sudo adduser $USER dialout
megalloid@megalloid-xubuntu:~$ cd ~/Xilinx/Vivado/2023.2/data/xicom/cable_drivers/lin64/install_script/install_drivers
megalloid@megalloid-xubuntu:~/Xilinx/Vivado/2023.2/data/xicom/cable_drivers/lin64/install_script/install_drivers$ sudo ./install_drivers
INFO: Installing cable drivers.
INFO: Script name = ./install_drivers
INFO: HostName = megalloid-xubuntu
INFO: RDI_BINROOT= .
INFO: Current working dir = /home/megalloid/Xilinx/Vivado/2023.2/data/xicom/cable_drivers/lin64/install_script/install_drivers
INFO: Kernel version = 6.5.0-41-generic.
INFO: Arch = x86_64.
Successfully installed Digilent Cable Drivers
--File /etc/udev/rules.d/52-xilinx-ftdi-usb.rules exists.
--File /etc/udev/rules.d/52-xilinx-ftdi-usb.rules version = 0001
--File 52-xilinx-ftdi-usb.rules exists.
--File 52-xilinx-ftdi-usb.rules version = 0001
--File 52-xilinx-ftdi-usb.rules is already updated.
--File /etc/udev/rules.d/52-xilinx-pcusb.rules does not exist.
--File version of /etc/udev/rules.d/52-xilinx-pcusb.rules = 0000.
--Updating rules file.
INFO: Digilent Return code = 0
INFO: Xilinx Return code = 0
INFO: Xilinx FTDI Return code = 0
INFO: Return code = 0
INFO: Driver installation successful.
CRITICAL WARNING: Cable(s) on the system must be unplugged then plugged back in order for the driver scripts to update the cables.
❯ Вывод списка устройств в JTAG
После того как выполнили все действия из предыдущего этапа необходимо отключить устройство от ПК и подключить обратно, а в терминале XSCT выполнить следующее:
xsct% targets
xsct% disconnect
xsct% Info: tcfchan#2 closed
xsct% connect
tcfchan#3
xsct% targets
1 APU
2 ARM Cortex-A9 MPCore #0 (Running)
3 ARM Cortex-A9 MPCore #1 (Running)
4 xc7z020
xsct%
Команда targets выводит список устройств, подключенных к JTAG. Всё, устройство детектируется. Идём к следующему шагу.
В зависимости от используемого отладчика, схемотехники цепей JTAG следует выбрать частоту тактирования JTAG. Примеры подобных ошибок вы можете увидеть ниже:
xsct% targets
1 whole scan chain (Unknown device configuration)
xsct% targets
1 whole scan chain (Unknown IR length)
xsct% targets
1 whole scan chain (too many devices)
При появлении подобных ошибок можно изменить частоту тактирования JTAG. Для вывода поддерживаемых частот необходимо сделать следующее:
xsct% jtag target 1
xsct% jtag frequency -list
125000 250000 500000 1000000 2000000 3000000 3750000 5000000 6000000 7500000 10000000 15000000 30000000
xsct% jtag frequency
15000000
При работе с ZynqMini я смело выставляю частоту 30000000 и все работает очень быстро:
xsct% jtag frequency 30000000
30000000
Идем дальше.
❯ Загрузка bitstream в Zynq через JTAG
Чтобы начать проверку частей полученного проекта на плате в первую очередь необходимо загрузить bitstream-файл в PL-часть. Для этого необходимо сделать следующее:
xsct% targets
1* APU
2 ARM Cortex-A9 MPCore #0 (Running)
3 ARM Cortex-A9 MPCore #1 (Running)
4 xc7z020
xsct% targets 4
xsct% fpga /home/megalloid/Xilinx/Projects/ZynqMini/1.Linux/top_design_wrapper.bit
100% 3MB 3.3MB/s 00:01
Сразу же происходит загрузка образа FPGA и загорается светодиод DONE.
❯ Загрузка FSBL
Следующим этапом можно загрузить First Stage Bootloader. Это второй загрузчик, который вступает в работу после BootROM. Загрузка выполняется не менее просто:
xsct% targets -set -nocase -filter {name =~ "arm*#0"}
xsct% dow /home/megalloid/Xilinx/Projects/ZynqMini/1.Linux/Vitis/zynq_fsbl/build/zynq_fsbl.elf
Downloading Program -- /home/megalloid/Xilinx/Projects/ZynqMini/1.Linux/Vitis/zynq_fsbl/build/zynq_fsbl.elf
section, .text: 0x00000000 - 0x0001045f
section, .handoff: 0x00010460 - 0x000104ab
section, .note.gnu.build-id: 0x000104ac - 0x000104cf
section, .init: 0x000104d0 - 0x000104db
section, .fini: 0x000104dc - 0x000104e7
section, .rodata: 0x000104e8 - 0x000110d0
section, .data: 0x000110d8 - 0x00013c0f
section, .mmu_tbl: 0x00014000 - 0x00017fff
section, .ARM.exidx: 0x00018000 - 0x00018007
section, .init_array: 0x00018008 - 0x0001800f
section, .fini_array: 0x00018010 - 0x00018013
section, .rsa_ac: 0x00018014 - 0x0001903f
section, .bss: 0x00019040 - 0x0001a3f3
section, .drvcfg_sec: 0x0001a3f4 - 0x0001a4b7
section, .heap: 0x0001a4b8 - 0x0001c4bf
section, .stack: 0xffff0000 - 0xffffd3ff
Setting PC to Program Start Address 0x00000000
Successfully downloaded /home/megalloid/Xilinx/Projects/ZynqMini/1.Linux/Vitis/zynq_fsbl/build/zynq_fsbl.elf
xsct% Info: ARM Cortex-A9 MPCore #0 (target 2) Stopped at 0xffffff28 (Suspended)
Запуск осуществляется на 1-м ядре ARM PS-части. Запускаем FSBL:
xsct% con
Если при компиляции FSBL вы включили отладочный вывод, при запуске — то UART-терминале мы увидим следующее:
Xilinx First Stage Boot Loader
Release 2023.2 Aug 9 2024-15:21:41
Silicon Version 3.1
Boot mode is SD
SD: Unable to open file BOOT.BIN: 3
SD_INIT_FAIL
FSBL Status = 0xA009
Теперь разберем полученный вывод. Команда dow выполняет загрузку заданного исполняемого файла на указанный target и устанавливает соответствующий указатель команд ядра ARM в entry point. После установки счетчика процессор останавливает работу. После необходимо остановить выполнение вручную для выполнения последующей загрузки:
xsct% stop
Info: ARM Cortex-A9 MPCore #0 (target 2) Stopped at 0x11ac (Suspended)
Остановка необходима для того, чтобы остановить работу Memory Management Unit (MMU), т. к. он выполняет трансляцию физических адресов в логические и по сути мешает прямому чтению/записи в память.
FSBL выполнит загрузку в соответствии с установленными на плате джамперами, которые определяют источник загрузки. В случае ZynqMini необходимо выставить значение в позицию JTAG:
❯ Инициализация PS-части
В состав генерируемого содержимого при создании проект в Vivado входит не только bitstream-файл. Помимо этого в XSA-архиве присутствует скрипт инициализации PS-части. И после запуска FSBL для инициализации периферии необходимо предварительно извлечь XSA-архив и выполнить на отлаживаемой плате скрипт ps7_init.tcl:
xsct% targets
1 APU
2* ARM Cortex-A9 MPCore #0 (Suspended)
3 ARM Cortex-A9 MPCore #1 (Running)
4 xc7z020
xsct% targets 1
xsct% source /home/megalloid/Xilinx/Projects/ZynqMini/1.Linux/top_design_wrapper.xsa_FILES/ps7_init.tcl
xsct% ps7_init
xsct% ps7_post_config
Если просмотреть содержимое этого файла можно увидеть все шаги, которые необходимы для выполнения инициализации периферии. Файл достаточно большой и весь вывод я не буду приводить тут.
❯ Загрузка Device Tree Blob для U-Boot
Для работы U-Boot необходим бинарный файл Device Tree. Без этого файла U-Boot не сможет проинициализировать периферию, которая необходима для дальнейшей работы. Для загрузки Device Tree Blob в RAM необходимо выполнить следующее:
xsct% targets -set -nocase -filter {name =~ "arm*#0"}
xsct% set device_tree_offset 0x10000
0x10000
xsct% dow -data /home/megalloid/Xilinx/Tools/u-boot-xlnx/arch/arm/dts/zynqmini.dtb ${device_tree_offset}
100% 0MB 0.6MB/s 00:00
Successfully downloaded /home/megalloid/Xilinx/Tools/u-boot-xlnx/arch/arm/dts/zynqmini.dtb
Опция -data необходима для того, чтобы указать, что этот файл не является исполняемым. Смещение, которое использовано в качестве переменной задается при компиляции U-Boot в параметре Default DTB pickup address.
❯ Загрузка U-Boot
Для того, чтобы осуществить загрузку Linux необходимо запустить скомпилированный файл U-Boot на плате. Сделать этого можно следующим образом:
xsct% dow /home/megalloid/Xilinx/Tools/u-boot-xlnx/u-boot.elf
Downloading Program -- /home/megalloid/Xilinx/Tools/u-boot-xlnx/u-boot.elf
section, .data: 0x04000000 - 0x040fb453
100% 0MB 0.5MB/s 00:01
Setting PC to Program Start Address 0x04000000
Successfully downloaded /home/megalloid/Xilinx/Tools/u-boot-xlnx/u-boot.elf
xsct% con
Info: ARM Cortex-A9 MPCore #0 (target 2) Running
Обратим внимание в UART-терминал:
U-Boot 2023.01 (Aug 09 2024 - 19:31:07 +0300)
CPU: Zynq 7z020
Silicon: v3.1
DRAM: ECC disabled 512 MiB
Core: 19 devices, 13 uclasses, devicetree: board
Flash: 0 Bytes
NAND: 0 MiB
MMC: mmc@e0100000: 0
Loading Environment from FAT... *** Error - No Valid Environment Area found
*** Warning - bad env area, using default environment
In: serial@e0001000
Out: serial@e0001000
Err: serial@e0001000
Net:
ZYNQ GEM: e000b000, mdio bus e000b000, phyaddr 0, interface rgmii-id
Warning: ethernet@e000b000 (eth0) using random MAC address - b2:ba:f7:7d:a1:49
eth0: ethernet@e000b000
Hit any key to stop autoboot: 0
Zynq>
Видим, что периферия проинициализирована и U-Boot запустился. Переходим к загрузке образа Linux.
❯ Загрузка Linux
Последний шаг, который необходимо выполнить для загрузки — загрузить в RAM оставшиеся компоненты: Linux Kernel, Device Tree Blob, RootFS. При этом очень важно правильно рассчитать адреса для загрузки этих компонентов так, чтобы один случайно не перезаписал другой. В идеале лучше всего грузить единый, скомпонованный в один файл, образ FIT Image, но я покажу как загрузить отдельные компоненты через XSCT через консоль:
xsct% targets -set -nocase -filter {name =~ "arm*#0"}
xsct% set device_tree_offset 0x1f00000
0x1f00000
xsct% set linux_kernel_offset 0x3000000
0x3000000
xsct% set rootfs_offset 0x2000000
0x2000000
xsct% stop
xsct% dow -data /home/megalloid/Xilinx/Tools/u-boot-xlnx/arch/arm/dts/zynqmini.dtb ${device_tree_offset}
100% 0MB 0.3MB/s 00:00
Successfully downloaded /home/megalloid/Xilinx/Tools/u-boot-xlnx/arch/arm/dts/zynqmini.dtb
xsct% dow -data /home/megalloid/Xilinx/Tools/linux-xlnx/arch/arm/boot/uImage ${linux_kernel_offset}
100% 4MB 0.4MB/s 00:10
Successfully downloaded /home/megalloid/Xilinx/Tools/linux-xlnx/arch/arm/boot/uImage
xsct% dow -data /home/megalloid/Xilinx/Tools/buildroot/images/rootfs.cpio.uboot ${rootfs_offset}
100% 4MB 0.5MB/s 00:09
Successfully downloaded /home/megalloid/Xilinx/Tools/buildroot/images/rootfs.cpio.uboot
xsct% con
После загрузки образов в оперативную память необходимо передать их на исполнение уже используя встроенные средства U-Boot через команду bootm в UART-терминале:
Zynq> bootm 0x3000000 0x2000000 0x1f00000
И наблюдаем как запускается ядро Linux:
## Booting kernel from Legacy Image at 03000000 ...
Image Name: Linux-6.1.0-xilinx
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 4624016 Bytes = 4.4 MiB
Load Address: 00008000
Entry Point: 00008000
Verifying Checksum ... OK
## Loading init Ramdisk from Legacy Image at 02000000 ...
Image Name:
Image Type: ARM Linux RAMDisk Image (uncompressed)
Data Size: 4940379 Bytes = 4.7 MiB
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
## Flattened Device Tree blob at 01f00000
Booting using the fdt blob at 0x1f00000
Working FDT set to 1f00000
Loading Kernel Image
Loading Ramdisk to 1e61c000, end 1ead225b ... OK
Loading Device Tree to 1e616000, end 1e61bd8b ... OK
Working FDT set to 1e616000
Starting kernel ...
Booting Linux on physical CPU 0x0
Linux version 6.1.0-xilinx (megalloid@megalloid-xubuntu) (arm-linux-gnueabihf-gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0, GNU ld (GNU Binutils for Ubuntu) 2.38) #1 SMP PREEMPT Fri Aug 9 21:45:24 MSK 2024
...
root@zynq:~ > uname -r
Linux-6.1.0-xilinx
Если все образы были собраны корректно то произойдет загрузка Linux и всего необходимого для работы.
❯ Заключение
Когда я освоил этот инструмент, время на отладку сократилось значительно, потому что раньше приходилось постоянно мучаться с пересборкой комплексного файла BOOT.bin и перекидывать это на microSD, возиться с кард-ридерами и прочим. Теперь процесс проверки ускорился, прямо скажем, значительно. И в качестве бонуса — для XSCT можно подготовить TCL-скрипт, который будет выполнять все эти действия автоматически.
Пользуйтесь на здоровье. Благодарю за внимание.
📚 Читайте также:
➤ Сложно о простом. Сеансовый уровень (L5), представительный (L6) уровень и прикладной (L7) уровень;
➤ Большое руководство по сетям и шифрованию трафика в Linux.
Новости, обзоры продуктов и конкурсы от команды Timeweb.Cloud — в нашем Telegram-канале ↩