EJTAG: аттракцион для хакеров

в 9:15, , рубрики: barebox, diy или сделай сам, EJTAG, FT2232, mips, openocd, Железо, Процессоры, Софт

EJTAG: аттракцион для хакеров - 1
Кампания по продвижению нанокомпьютера black swift в самом разгаре (см. также публикацию на habrahabr). black swift построен на базе SoC Atheros AR9331, что позволило сделать его с одной стороны крошечными, недорогим, и малопотребляющим, а с другой стороны в распоряжении пользователя находится процессорное ядро MIPS 24Kc, работающее на частоте до 400 МГц.
Недавно на форуме black-swift.ru был задан вопрос

Есть потребность в документации по использованию JTAG-интерфейса в устройстве. Можно ли ожидать чего-нибудь в этом направлении?

В данной публикации я вставлю свои пять копеек приведу конкретный простой сценарий использования JTAG-интерфейса SoC Atheros AR9331 для отладки программного обеспечения.
Публикация может быть интересна не только разработчикам ПО для AR9331, но и всем интересующимся внутрисхемной отладкой на процессорах с архитектурой MIPS при помощи свободного ПО.

Плат black swift в свободном доступе на момент написания данной публикации ещё нет, однако доступны готовые устройства на базе SoC Atheros AR9331; для демонстрации я буду использовать TP-Link MR3020.
Различие между MR3020 и black swift минимально, более того, освоившему работу с MR3020 переход на black swift может показаться даже облегчением: подключаться к внешним интерфейсам SoC станет проще, а программных препонов меньше.
План демонстрации: мы остановим процессор сразу после старта и запустим на нём вместо штатного зашитого в ПЗУ загрузчика U-Boot другой загрузчик — barebox.
Какую пользу (применительно к MR3020) можно извлечь от использования EJTAG?

  • ребята из TP-Link наложили ограничения на внесения изменений в прошивку устройства (хотя, они не очень сильно старались) — возможность использовать EJTAG снимает эти ограничения;
  • возможность использовать EJTAG сразу после старта процессора значительно упрощает отладку начальной стадии загрузчика barebox (действительно, использовать EJTAG гораздо комфортнее, нежели возиться с перепрошивкой загрузочного ПЗУ на программаторе);
  • EJTAG позволяет восстановить работоспособность устройства после «окирпичивания» в результате порчи содержимого загрузочного ПЗУ.

Чтобы не доходить до уровня изложения «делай раз, делай два, нажми на кнопку — получишь результат» я постараюсь давать минимальные пояснения. Начать стоит с пояснения того, что такое EJTAG.

EJTAG в процессорах с архитектурой MIPS

Без стадии отладки не обходится разработка никакого программного продукта, и счастье программисту, если в его распоряжении имеется толковый отладчик (англ. debugger).
Разработчики ПО для *nix или Windows могут воспользоваться развитыми средствами отладки — можно прогнать свою программу шаг за шагом, посмотреть значения переменных в тот или иной момент времени, поставить точки останова.
Но как быть разработчику ПО для встраиваемой системы? Такое ПО может работать вне окружения какой-либо ОС, а сама встраиваемая система мало похожа на ПК — ни клавиатуры ни монитора как правило нет.
Для того чтобы как-то упростить жизнь в описанной ситуации придумана технология внутрисхемной отладки (англ. in-circuit debugging), которая заключается в следующем: в состав процессора вводится специальный блок (назовём его «блок отладки»), следящий за процессом исполнения инструкций и способный на него повлиять. Этот блок действует не сам по себе, но по командам пользователя (каковым является программист, проводящий отладку ПО). Для внешнего управления этим блоком отладки часто используется интерфейс JTAG.

Почему именно JTAG? JTAG является последовательной шиной (возможно использовать только 4 сигнала), позволяющей соединять десятки устройств (возможно очень разных устройств!) в цепочку, и по мере необходимости передавать команды каждому из устройств. JTAG широко используется для тестирования соединений в печатных платах — в настоящее время БИС любой мало-мальски нетривиальной платы соединены в цепочку JTAG. Вполне резонно использовать JTAG не только для проверки соединений, но и для доставки в процессор команд управления отладкой.

Для процессоров MIPS стандартным является набор аппаратных и программных средств для внутрисхемной отладки под названием EJTAG. EJTAG стандартизирован в документах MIPS EJTAG Specification; существует сразу несколько версий этой спецификации; к примеру в состав процессорного ядра 24Kc входит блок отладки, соответствующий спецификации EJTAG 2.60.

Таким образом не надо смешивать JTAG и EJTAG: JTAG это интерфейс передачи данных; EJTAG — это стандартный для MIPS способ проводить внутрисхемную отладку, при котором используется JTAG.

Что надо для работы с EJTAG?

  1. Процессор MIPS с поддержкой EJTAG (англ. target или целевой процессор);
  2. Инструментальная ЭВМ с которой мы будем управлять целевым процессором;
  3. Устройство, обеспечивающее подключение ЭВМ к интерфейсу JTAG (англ. dongle);
  4. ПО, которое исполняется на инструментальной ЭВМ, получает от пользователя указания по управлению целевым процессором, и через dongle отправляющее в целевой процессор необходимые команды.

Сразу заметим, что от пользователя не требуются глубокие знания по организации EJTAG, указания по управлению целевым процессором вполне абстрактны, например:

  • остановить исполнение инструкций процессором;
  • начать исполнение инструкций с адреса такого-то;
  • выполнить одну инструкцию и остановиться;
  • посмотреть содержимое регистров процессора.

Для нашей демонстрации будем использовать:

  1. процессор с EJTAG — MIPS 24Kc из состава SoC Atheros AR9331;
  2. инструментальная ЭВМ — ПК с процессором с архитектурой x86/amd64, работающий под управлением ОС Debian Linux (хотя другие ОС на базе Linux тоже подойдут);
  3. JTAG dongle — макетная плата с микросхемой FT2232H (а именно microsin.net/adminstuff/hardware/ft2232h-board.html) (далее просто макетка);
  4. ПО для управления AR9331 через EJTAG — openocd (http://openocd.sourceforge.net/).

Кроме того, очень желательно подключиться также к интерфейсу UART AR9331, он пригодится для взаимодействия с программами, исполняющимися на процессоре (без подключения к UART демонстрация была бы довольно скучной). Для отправки и приёма символов в UART AR9331 используем программу minicom.
Макетка FT2232H обеспечивает подключение сразу и к UART и к JTAG.

Для взаимодействия с инструментальной ЭВМ будет использоваться интерфейс командной строки, так что готовьте ваши терминалы.

Подключение к макетки FT2232H к MR3020

Вот схема подключения (см. также статью на wikidevi.com):

EJTAG: аттракцион для хакеров - 2

Кому-то такая схема подключения JTAG покажется варварством, но в нашей простой ситуации она вполне оправдана.

Внешний вид MR3020 с подключённой макеткой FT2232H:
EJTAG: аттракцион для хакеров - 3

Подключение к UART

Вывод интерфейса UART из MR3020 не представляет проблем: на плате уже есть отверстия для впайки штырей.

EJTAG: аттракцион для хакеров - 4

Обозначения TX и RX на фотографии указаны с точки зрения AR9331, т.е. TX AR9331 (pin 1 на плате) надо подключать к RX FT2232 (BDBUS1).
Рекомендую подключить UART MR3020 к макетке, а саму макетку к инструментальной ЭВМ, и затем, включив питание MR3020, пронаблюдать при помощи minicom сообщения штатного загрузчика U-Boot.
Вот что для этого надо выполнить ряд шагов.

Проверка подключеня макетки к инструментальной ЭВМ

Подключить UART MR3020 к макетке; подключить макетку FT2232H к инструментальной ЭВМ по USB; на инструментальной ЭВМ в командной строке запустить dmesg — убедиться, что появились сообщения вроде

[1573965.608101] usb 1-2: new high-speed USB device number 63 using ehci-pci
[1573965.740851] usb 1-2: New USB device found, idVendor=0403, idProduct=6010
[1573965.740862] usb 1-2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[1573965.740868] usb 1-2: Product: Dual RS232-HS
[1573965.740874] usb 1-2: Manufacturer: FTDI
[1573965.741737] ftdi_sio 1-2:1.0: FTDI USB Serial Device converter detected
[1573965.741938] usb 1-2: Detected FT2232H
[1573965.741948] usb 1-2: Number of endpoints 2
[1573965.741957] usb 1-2: Endpoint 1 MaxPacketSize 512
[1573965.741966] usb 1-2: Endpoint 2 MaxPacketSize 512
[1573965.741974] usb 1-2: Setting MaxPacketSize 512
[1573965.742920] usb 1-2: FTDI USB Serial Device converter now attached to ttyUSB0
[1573965.743493] ftdi_sio 1-2:1.1: FTDI USB Serial Device converter detected
[1573965.743662] usb 1-2: Detected FT2232H
[1573965.743672] usb 1-2: Number of endpoints 2
[1573965.743681] usb 1-2: Endpoint 1 MaxPacketSize 512
[1573965.743690] usb 1-2: Endpoint 2 MaxPacketSize 512
[1573965.743699] usb 1-2: Setting MaxPacketSize 512
[1573965.744669] usb 1-2: FTDI USB Serial Device converter now attached to ttyUSB1

Из этого сообщения следует, что на инструментальной ЭВМ появились два новых последовательных интерфейса /dev/ttyUSB0 и /dev/ttyUSB1. В соответствии со схемой подключения к UART MR3020 оказывается подключён второй из двух интерфейсов, то есть /dev/ttyUSB1.

Установка и настройка minicom

Установка программы minicom в основанных на Debian дистрибутивах очень проста:

$ sudo apt-get install minicom

Программа minicom очень добра к новичку — все настройки можно провести через меню, однако эта доброта имеет и обратную сторону — довольно неудобно объяснять как именно выставить необходимые настройки.
Чтобы не связываться с системой меню minicom поступим проще — произведём настройки при помощи конфигурационного файла. Для простоты сделаем глобальный конфигурационный файл, для этого от root'а выполним:

# cat <<EOF > /etc/minicom/minirc.USB1
pu port             /dev/ttyUSB1
pu baudrate         115200
pu escape-key       ^B
pu rtscts           No
EOF

Замечание для пользователей не-Debian дистрибутивов: конфигурационные файлы для minicom могут располагаться в месте, отличном от /etc/minicom/.

Указанный конфигурационный файл говорит minicom'у, что отклонения от настроек по умолчанию заключаются в следующем:

  1. используется порт /dev/ttyUSB1;
  2. настроить скорость порта 115200;
  3. клавиша начала команд minicom — ctrl-b; например, для вызова главного меню надо нажать ctrl-b, затем z;
  4. аппаратное управление потоком отключено (действительно, для подключения мы использовали только линии RX и TX, какое уж там аппаратное управление потоком).

Запуск minicom

Для простоты запустим minicom от root'а;

# minicom USB1

При этом minicom использует настройки из файла /etc/minicom/minirc.USB1 (если конечно файл ~/.minirc.USB1 не существует).

конечно более грамотно добавить своего пользователя в группу dialout...; но давайте не будем усложнять.

Теперь включаем питание MR3020 и наблюдаем в minicom сообщения от U-Boot:

U-Boot 1.1.4 (Aug 17 2012 - 15:21:03)

AP121 (ar9330) U-boot

DRAM:  32 MB
led turning on for 1s...
id read 0x100000ff
flash size 4194304, sector count = 64
Flash:  4 MB
Using default environment

Далее будут выданы сообщения о загрузки linux, но они нам не очень-то и интересны; если какой-то разумный вывод из UART поступает, то можно переходить к подключению JTAG.

Подключение к JTAG

Подключение к JTAG не тривиально, но возможно. См. статью на wikidevi.com.
Кроме четырёх линий JTAG необходимо также обеспечить отключение загрузочного ПЗУ; в статье на wikidevi.com для этого предлагается разрывать линию ChipSelect при помощи перемычки (джампера). Дело в том, что штатный загрузчик U-boot, находящийся в ПЗУ, почти сразу после старта блокирует работу JTAG.
В случае же старта процессора с неработающим ПЗУ ничего страшного не произойдёт, процессор будет вместо программы из ПЗУ выполнять «мусор». Процессор попадёт в сложное положение, но EJTAG останется доступным.
После того, как все линии JTAG оказались соединены с соответствующими выводами FT2232H, а загрузочное ПЗУ отключено, можно попробовать просканировать JTAG-цепочку при помощи openocd. Но прежде чем запустить openocd, его придётся установить и настроить...
Установка программы openocd не сложнее установки minicom:

$ sudo apt-get install openocd

openocd: начальная настройка

В openocd встроен язык tcl, все сценарии работы и конфигурационные файлы пишутся на нём. Однако для нашего простейшего случая конфигурационный файл будет совсем прост.
Создадим файл ft2232h-scan.cfg, в котором укажем openocd, что будем использовать dongle на базе FT2232H для доступа к JTAG:

$ cat <<EOF > ft2232h-scan.cfg
interface ftdi
ftdi_vid_pid 0x0403 0x6010
ftdi_layout_init 0x0018 0x05fb
adapter_khz 100
shutdown
EOF

В этом файле мы укажем, что для подключения к JTAG будем использовать «драйвер» ftdi, который и обслуживает все многочисленные dongl'ы на базе FT2232H. Опция ftdi_vid_pid указывает Vendor ID и Device ID микросхемы FT2232H на шине USB (по умолчанию это как раз 0x0403 0x6010; эти ID были в выводе dmesg, в любой момент их можно просмотреть при помощи программы lsusb). Опция ftdi_layout_init указывает настройки GPIO выходов FT2232H. Опция adapter_khz определяет максимальную частоту тактового сигнала JTAG; 100 КГц (невысокая частота) хорошо подходит для сканирования.
Директива shutdown заставит openocd завершить работу сразу после сканирования JTAG.
Давайте запустим openocd от root'а (Внимание! Запускать openocd следует после включения питания MR3020, причем в момент включения питания должна быть нажата кнопка SW2 на плате MR3020; также не забудьте заблокировать загрузочное ПЗУ):

# openocd -f ft2232h-scan.cfg
Open On-Chip Debugger 0.8.0 (2014-10-20-22:02)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.sourceforge.net/doc/doxygen/bugs.html
Info : only one transport option; autoselect 'jtag'
adapter speed: 100 kHz
shutdown command invoked
Info : clock speed 100 kHz
Warn : There are no enabled taps.  AUTO PROBING MIGHT NOT WORK!!
Warn : AUTO auto0.tap - use "jtag newtap auto0 tap -expected-id 0x00000001 ..."
Warn : AUTO auto0.tap - use "... -irlen 5"
Warn : gdb services need one or more targets defined

В этом выводе наибольшего внимания заслуживают строчки, содержащие AUTO auto0.tap — в них приводится информация о найденных абонентах JTAG (tap-контроллерах), причём сразу приводится пример строки которую надо занести в конфигурационный файл openocd для работы со свежеобнаруженным tap-контроллером.
Воспользуемся этими строчками и создадим конфигурационный файл для openocd, который обеспечит загрузку в ОЗУ образа загрузчика barebox.
Но прежде чем грузить образ barebox, его надо где-то взять; а так как готовых подходящих образов нигде нет, будет собирать образ самостоятельно из исходных текстов.

Сборка barebox

Образ barebox для AR9331 должен состоять из инструкций процессора MIPS32, а наша инструментальная ЭВМ почти наверняка построена на базе процессора с системой команд x86 или amd64 (так их, во всяком случае, называет Debian).
Для того, чтобы при помощи процессора x86/amd64 породить инструкции MIPS32, нам понадобится кросс-компилятор (то есть компилятор, который исполняется на ЭВМ с одной архитектурой команд, а генерирует код для ЭВМ с другой системой команд).
Сборка кросс-компилятора с требуемыми свойствами — задача совсем не тривиальная и для её облегчения создано немало всяких инструментов, известных по ключевым словам buildroot, openwrt, crosstool-ng.
Однако в этой демонстрации мы пойдём простым путём — скачаем готовый кросс-компилятор от MentorGraphics.
Итак, скачиваем и распаковываем в /opt готовый кросс-компилятор:

$ wget http://sourcery.mentor.com/public/gnu_toolchain/mips-linux-gnu/mips-2014.11-22-mips-linux-gnu-i686-pc-linux-gnu.tar.bz2
$ sudo tar fx mips-2014.11-22-mips-linux-gnu-i686-pc-linux-gnu.tar.bz2 -C /opt

В результате, к примеру, путь к кросс-компилятору Си будет таким: /opt/mips-2014.11/bin/mips-linux-gnu-gcc.
Теперь скачаем и распакуем исходные тексты загрузчика barebox:

$ wget http://barebox.org/download/barebox-2015.01.0.tar.bz2
$ tar fx barebox-2015.01.0.tar.bz2

Произведём сборку barebox:

$ cd barebox-2015.01.0
$ make ARCH=mips tplink-mr3020_defconfig
$ make ARCH=mips CROSS_COMPILE=/opt/mips-2014.11/bin/mips-linux-gnu-
$ cd ..

Если всё прошло хорошо, то получим файл barebox-2015.01.0/barebox.bin.

openocd: более полная настройка

Теперь у нас есть то, что мы можем грузить в ОЗУ MR3020; парадоксально, но у нас нет самого ОЗУ!
Дело в том, что когда для сохранения работоспособности EJTAG мы отключили загрузочное ПЗУ вместе с ним мы отключили начальную инициализацию аппаратуру AR9331, в том числе инициализацию контроллера ОЗУ и контроллера UART.
На наше счастье, последовательность записей в регистры для инициализации аппаратуры уже известна.
Окончательно файл ft2232h-mr3020.cfg, который обеспечит подключение к блоку отладки AR9331, начальную инициализацию аппаратуры, загрузку образа barebox.bin в ОЗУ MR3020 по адресу 0xa0100000 и запуск его на выполнение выглядит так:

interface ftdi
ftdi_vid_pid 0x0403 0x6010
ftdi_layout_init 0x0018 0x05fb
adapter_khz 600

jtag newtap auto0 tap -expected-id 0x00000001 -irlen 5
target create auto0.tap mips_m4k -endian big -chain-position auto0.tap

init
halt

# pll initialization
mww 0xb8050008 0x00018004
mww 0xb8050004 0x00000352
mww 0xb8050000 0x40818000
mww 0xb8050010 0x001003e8
mww 0xb8050000 0x00818000
mww 0xb8050008 0x00008000
sleep 1

# Setup DDR1 config and flash mapping
mww 0xb8000000 0x7fbc8cd0
mww 0xb8000004 0x9dd0e6a8

mww 0xb8000010 0x8
mww 0xb8000008 0x133
mww 0xb8000010 0x1
mww 0xb800000c 0x2
mww 0xb8000010 0x2
mww 0xb8000010 0x8
mww 0xb8000008 0x33
mww 0xb8000010 0x1
mww 0xb8000014 0x4186
mww 0xb800001c 0x8
mww 0xb8000020 0x9
mww 0xb8000018 0xff

# UART
mww 0xb8020004 0x4388
mww 0xb8020008 0xc2000

# GPIO
mww 0xb8040028 0x48002

load_image barebox-2015.01.0/barebox.bin 0xa0100000 bin
resume 0xa0100000
shutdown

В openocd принята довольно разумная практика, при которой описание dongl'а, описание целевого процессора, а также текущий сценарий отладки принято размещать в разных файлах, но в этой публикации для упрощения изложения мы так поступать не будем.

openocd: загрузка barebox

Итак, загрузим и запустим barebox (Не забудьте про джампер отключения ПЗУ. Также не забывайте держать нажатой кнопку SW2 в момент включения питания MR3020! Наберитесь терпения — загрузка занимает более 100 секунд):

# openocd -f ft2232h-mr3020.cfg 
Open On-Chip Debugger 0.8.0 (2014-10-20-22:02)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.sourceforge.net/doc/doxygen/bugs.html
Info : only one transport option; autoselect 'jtag'
adapter speed: 600 kHz
Info : clock speed 600 kHz
Info : JTAG tap: auto0.tap tap/device found: 0x00000001 (mfg: 0x000, part: 0x0000, ver: 0x0)
target state: halted
target halted in MIPS32 mode due to debug-request, pc: 0xb0ddd068
Error: No working memory available. Specify -work-area-phys to target.
Warn : not enough working area available(requested 128)
Error: No working area available
Warn : Falling back to non-bulk write
185568 bytes written at address 0xa0100000
downloaded 185568 bytes in 102.970634s (1.760 KiB/s)
shutdown command invoked

После окончания работы openocd в окне minicom мы можем наблюдать сообщения о старте barebox'а:

barebox 2015.01.0 #1 Thu Jan 29 02:13:17 MSK 2015

Board: TP-LINK MR3020
m25p80 m25p80@00: unrecognized JEDEC id 900040
m25p80 m25p80@00: probe failed: No such device
malloc space: 0xa0400000 -> 0xa07fffff (size 4 MiB)
environment load /dev/env0: No such file or directory
running /env/bin/init...
/env/bin/init not found
barebox:/

Далее желающие могут поиграть с командами barebox, список которых откроется по команде help.
Обратите внимание на сообщение об ошибке probe failed: No such device, оно появилось из-за того, что barebox попытался «нащупать» загрузочное ПЗУ на шине SPI. Но так как для оживления EJTAG загрузочное ПЗУ было отключено, то попытка barebox'а чего-либо найти обречена на неудачу.
Если исхитриться надеть перемычку, отключающую загрузочное ПЗУ во время загрузки barebox в память, то можно вместо

m25p80 m25p80@00: unrecognized JEDEC id 900040

наблюдать более оптимистическое

m25p80 m25p80@00: s25sl032p (4096 Kbytes)

Хотя barebox-2015.01.0 поддерживает аппаратуру SoC AR9331 в минимальном объёме (интерфейсы USB и Ethernet не поддерживаются), но прочитать и записать загрузочное ПЗУ barebox'у вполне по силам.

Что дальше? (вместо послесловия)

Загрузка данных в ОЗУ — это не предел возможностей EJTAG. Но нельзя объять необъятное — в публикации не освещены вопросы собственно отладки — этот материал остаётся для будущих публикаций.
Законное негодование вызывает низкая скорость передачи данных — менее 2 Кбайт в секунду, этот момент также надо попытаться исправить.

Благодарности

Автор выражает благодарность людям, без участия которых данная публикация едва ли была бы возможна:

  • Алексею Ремпелю, который освоил подключение к JTAG MR3020 и опубликовал свои заметки;
  • Алексею Соколову, который совершенно ювелирно припаял провода к резисторам платы моего экземпляра MR3020;
  • Петру Мамонову, за разъяснения мне деталей работы EJTAG и различных dongl'ов.

Автор: Frantony

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js