[Перевод] Записки разработчика Intel System Studio: отладка Linux-ядра Android с помощью Intel JTAG Debugger и MinnowBoard MAX

f300cb32739c48378cf14d65a6484061.png Инструменты отладки нужны каждому разработчику. Однако, не существует универсальных решений, подходящих и тем, кто создаёт приложения пользовательского уровня, и тем, кто пишет низкоуровневые программы, вроде драйверов оборудования. Чем ближе к «железу» — тем больше хардкора в отладке и тестировании.

Из этого материала вы узнаете о том, как отлаживать код и анализировать исключения на уровне ядра Linux ОС Android в системах, основанных на архитектуре Intel. А именно, мы рассмотрим отладочный инструмент JTAG Debugger, который является частью пакета Intel System Studio Ultimate Edition. Мы расскажем о стандарте JTAG, о вышеупомянутом JTAG-отладчике Intel, об обработке исключений. В качестве примера мы будем использовать мини-компьютер MinnowBoard MAX с Intel Atom на борту.

Обзор JTAG


JTAG (произносится как «джей-таг», «jay-tag») — это сокращение от Joint Test Action Group. Обычно, когда говорят «JTAG», подразумевают стандарт IEEE 1149.1–1990 (IEEE Standard Test Access Port and Boundary-Scan Architecture). Этот стандарт устанавливает правила отладки и тестирования однокристальных систем (SoC, System on Chip) и программного обеспечения микропроцессоров (Microprocessor Software).

При JTAG-отладке используется набор инструментов, состоящий из трёх частей: программный JTAG-отладчик, установленный на главном компьютере, аппаратный JTAG-адаптер (датчик) и внутрисхемный отладчик (OCD, On Chip Debug), которым оснащена тестируемая микросхема.

Программный JTAG-отладчик


JTAG-отладчик — это программный инструмент, установленный на главном компьютере. Он получает данные и сведения об адресах от JTAG-адаптера и отображает их в пользовательском интерфейсе. Разработчик, в свою очередь, может отправлять команды JTAG-адаптеру, который подключен к основному компьютеру по USB или с помощью другого интерфейса.

Пользуясь этим инструментом, можно контролировать выполнение программы и отлаживать её на уровне исходного кода. Подобное реализуется благодаря файлам символов, которые соответствуют двоичным образам, загружаемым на целевые системы. Эти средства дают разработчику следующие возможности: запуск (run) и остановка (stop) исполнения кода, выполнение в ходе отладки шага с обходом (step over) и шага с заходом (step into), указание точек останова (breakpoints), доступ к памяти.

Пользуясь вышеописанными средствами, программист может выполнять отладку программной части целевой системы, исследовать системную память и регистры.

Intel JTAG Debugger (известный как XDB), входит в состав Intel System Studio Ultimate Edition. XDB — это тот самый программный инструмент JTAG-отладки, который должен быть установлен на главном компьютере.

Аппаратный JTAG-адаптер


JTAG-адаптер — это устройство, которое преобразует JTAG-сигналы в формат, подходящий для передачи компьютеру. Для сопряжения адаптеров и ПК используются такие интерфейсы, как USB, параллельный порт, RS-232, Ethernet. USB — самый популярный среди них. Именно он применяется для связи многих JTAG-адаптеров с компьютерами. Стандартом предусмотрено минимальное число JTAG-контактов для подключения целевых устройств к JTAG-адаптерам, однако, на практике применяются самые разные интерфейсы. Например, это 10- и 20-контактные разъемы для ARM, 14-контактный для ST, 16-контактный для OCDS.

В связке из отладчика Intel JTAG и MinnowBoard MAX, о которой идёт речь в этом материале, используется 60-контактный разъем для подключения целевого устройства. В качестве JTAG-адаптера для MinnowBoard MAX применяется Intel ITP-XDP3. Отладчик Intel JTAG совместим и с JTAG-адаптерами других производителей. Например — с Macraigor Systems usb2Demon и OpenOCD.

Внутрисхемный отладчик (целевой микрочип)


Главные компоненты внутрисхемного отладчика — это TAP (Test Access Point, тестовый порт) и TDI (Test Data In, вход тестовых данных)/TDP (Test Data Out, выход тестовых данных). Используя TAP можно сбрасывать, читать и записывать состояние регистров, пользоваться инструкцией BYPASS. Основная технология, которая применяется в JTAG — это так называемое граничное сканирование (Boundary Scan) с использованием сигнальных линий TDI/TDO.

18f552fd2f2f4cb5303284689a6169f2.jpg
Конфигурация из JTAG-адаптера и целевой системы. Здесь же показана плата расширения, которая используется для соединения Intel ITP-XDP3 и MinnowBoard MAX

Обзор исключений в архитектуре Intel


Исключение (exception) — это синхронное событие, которое генерируется, когда процессор, при выполнении инструкций, обнаруживает одно или несколько предопределенных условий. Архитектура IA-32 предусматривает три класса исключений: отказ (fault), ловушка (trap) и авария (abort). Обычно при возникновении отказов и ловушек возможно продолжение прерванной работы, в то время как при авариях — нет. Когда возникает исключение, оно обрабатывается так же, как обрабатываются прерывания. Это означает, что после остановки и сохранения текущего процесса, система переключается на обработчик исключения, а после того, как обработчик завершил работу, возвращается к исполняемой ранее задаче.

Исключения и прерывания защищенного режима

Вектор Сокращённое наименование Описание Тип Код ошибки Источник
0
#DE
Ошибка деления
Отказ
Нет
Инструкции DIV и IDIV
1
#DB
Зарезервировано
Отказ / ловушка
Нет
Только для использования Intel
2
Прерывание NMI
Прерывание
Нет
Внешнее немаскируемое прерывание
3
#BP
Точка останова
Ловушка
Нет
Инструкция INT 3
4
#OF
Переполнение
Ловушка
Нет
Инструкция INT0
5
#BR
Выход за границы диапазона
Отказ
Нет
Инструкция BOUND
6
#UD
Неправильный (неопределенный) код операции
Отказ
Нет
Инструкция UD2 или зарезервированный код операции
7
#NM
Устройство недоступно (Нет математического сопроцессора)
Отказ
Нет
Инструкции вычислений с плавающей точкой или инструкции WAIT/FWAIT
8
#DF
Двойной отказ
Авария
Да (ноль)
Любая инструкция, которая может сгенерировать исключение, NMI или INTR
9
Выход за пределы сегмента сопроцессора (зарезервировано)
Отказ
Нет
Инструкция, выполняющая вычисления с плавающей точкой
10
#TS
Неверный TSS
Отказ
Да
Переключение задач или доступ к TSS
11
#NP
Сегмент отсутствует
Отказ
Да
Загрузка сегментных регистров или доступ к системным сегментам
12
#SS
Отказ сегмента стека
Отказ
Да
Операции со стеком и загрузка регистра SS
13
#GP
Общая ошибка защиты
Отказ
Да
Ошибки, связанные с памятью, проверками защиты
14
#PF
Отказ страницы
Отказ
Да
Работа с памятью
15

Зарезервировано Intel, не предназначено для использования
Нет
16
#MF
Ошибка вычислений с плавающей точкой x87 FPU (Ошибка вычислений)
Отказ
Нет
Вычисления с плавающей точкой на x87 FPU или инструкции WAIT/FWAIT
17
#AC
Ошибка проверки выравнивания
Отказ
Да (ноль)
Работа с данными в памяти
18
#MC
Аппаратная ошибка
Авария
Нет
Коды ошибок (если они есть) и их источник зависят от аппаратного обеспечения
19
#XM
Исключения вычислений с плавающей точкой SIMD
Отказ
Нет
Инструкции вычислений с плавающей точкой SSE, SSE2, SSE3
20
#VE
Исключение виртуализации
Отказ
Нет
EPT-нарушения
21 — 31
Зарезервировано Intel, не предназначено для использования
32 — 255
Прерывания, заданные разработчиком (не зарезервированы)
Прерывание
Внешние прерывания или инструкции INT n.


Подготовка MinnowBoard MAX и Intel ITP-XDP3 к подключению к главному компьютеру по USB


Для начала надо установить на MinnowBoard MAX ОС Android. Для того чтобы это сделать, обратитесь к материалу «Статья разработчика Intel System Studio: настройка, сборка и профилировка Linux-ядра Android с помощью VTune». Он содержит инструкцию по сборке, установке и настройке Android на MinnowBoard MAX.

После установки ОС подключим MinnowBoard MAX к JTAG-адаптеру Intel ITP-XDP3 с помощью платы расширения. JTAG-адаптер присоединим к ПК по USB. На главном компьютере должна быть установлена Intel System Studio Ultimate Edition, в состав которой входит USB-драйвер для Intel ITP-XDP3.

a4dd076e8e8f49d9cf2a483debf1ab16.jpg
MinnowBoard MAX подключён к JTAG-адаптеру Intel ITP-XDP3, который, в свою очередь, подключён к хост-компьютеру с установленным на нём JTAG-отладчиком от Intel (XDB)

Использование JTAG-отладчика Intel (XDB) для отладки ядра Android на MinnowBoard MAX


Рассмотрим пошаговую процедуру использования XDB в деле отладки Linux-ядра ОС Android.

1. Запустим JTAG-отладчик Intel. Для этого нужно перейти в папку, где он установлен, и запустить пакетный файл (например — start_xdb_legacy_products.bat).

2. Подключимся к целевому устройству. Для этого нужно, в интерфейсе JTAG-отладчика, выполнить команду File > Connect и выбрать, во-первых, аппаратный JTAG- адаптер. В нашем случае это Intel ITP-XPD3. Во-вторых — надо указать целевую платформу. Нас интересует Intel Atom Processor E38xx, Z3680, X37xx — 2 cores (ValleyView).

e91749146fa18866f22a836867897d78.png
Выбор аппаратного JTAG-адаптера и целевой платформы в XDB

3. Загрузим файлы символов и укажем директорию файлов исходного кода. Для этого нужно выполнить в JTAG-отладчике Intel команду File > Load / Unload Symbol и указать файлы символов. Для файлов исходного кода нужно выполнить команду Options > Source Directories и указать правила сопоставления файлов исходного кода и файлов символов, а так же соответствующие директории. Правила позволяют настроить соответствие путей в файле символов, которые записываются во время компиляции, и текущих мест расположения файлов исходного кода.

4. Найдём entry-файл, в котором имеется обработчик исключений. Воспользуемся командой меню JTAG-отладчика Intel View > Source files и откроем файл entry_64.S.

e03a36d73b96f5815d9d6bdd788e18ca.png
Поиск файла entry_64.S

5. Установим точку останова на точке входа исключения. Для этого найдём строку ENTRY (error_entry), которая является точкой входа исключения с кодом ошибки в регистре RAX. Каждый обработчик исключения определён как макрос zeroentry или errorentry. Таким образом, можно установить точку останова в error_entry или в каком-то конкретном обработчике. В данном материале мы используем для тестирования «zeroentry invalid_op do_invalid_op».

ENTRY(error_entry)
        XCPT_FRAME
        CFI_ADJUST_CFA_OFFSET 15*8
        /* oldrax contains error code */
        cld
        movq_cfi rdi, RDI+8
        movq_cfi rsi, RSI+8
        movq_cfi rdx, RDX+8
        movq_cfi rcx, RCX+8
        movq_cfi rax, RAX+8
        movq_cfi  r8,  R8+8
        movq_cfi  r9,  R9+8
        movq_cfi r10, R10+8
        movq_cfi r11, R11+8
        movq_cfi rbx, RBX+8
        movq_cfi rbp, RBP+8
        movq_cfi r12, R12+8
        movq_cfi r13, R13+8
        movq_cfi r14, R14+8
        movq_cfi r15, R15+8
        xorl %ebx,%ebx
        testl $3,CS+8(%rsp)
        je error_kernelspace
error_swapgs:
        SWAPGS
error_sti:
        TRACE_IRQS_OFF
        ret
<....>
zeroentry divide_error do_divide_error
zeroentry overflow do_overflow
zeroentry bounds do_bounds
zeroentry invalid_op do_invalid_op
zeroentry device_not_available do_device_not_available
paranoiderrorentry double_fault do_double_fault
zeroentry coprocessor_segment_overrun do_coprocessor_segment_overrun
errorentry invalid_TSS do_invalid_TSS
errorentry segment_not_present do_segment_not_present
zeroentry spurious_interrupt_bug do_spurious_interrupt_bug
zeroentry coprocessor_error do_coprocessor_error
errorentry alignment_check do_alignment_check
zeroentry simd_coprocessor_error do_simd_coprocessor_error


Теперь, в качестве примера, вызовем исключение, и проверим, сработал ли обработчик, на котором мы установили точку останова. Установим точку останова на «zeroentry invalid_op do_invalid_op» и вызовем блок кода BUG (), который выполняет инструкцию ud2, вызывающую отказ (fault) «Неправильный код операции».

#define BUG()                                                        \
do {                                                            \
        asm volatile("ud2");                                  \
        unreachable();                                          \
} while (0)


Вызов BUG ()


Макрос BUG () надо добавить в собственный тестовый код уровня ядра для того, чтобы было вызвано исключение. В данном примере мы добавили его в keyboard.c для того, чтобы исключение вызывалось при появлении особых последовательностей символов, вводимых с клавиатуры.

853be08948ea9b243e7d406a85fb0cc8.png
Результат вызова макроса BUG ()

ec6c1e262b42b894e6d1b9327a3230c9.png
Результат вызова макроса BUG (), увеличенный фрагмент копии экрана

Остановка на точке останова Invalid_op


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

942bbc3821b6a30dd653d98a9f956430.png
Точка останова в обработчике исключения «Неправильный код операции»

f2d9baf64e4f08380b7f387470696060.png
Точка останова в обработчике исключения «Неправильный код операции», увеличенный фрагмент копии экрана

Заключение


Некоторые исключения — это критические ошибки аппаратного и программного обеспечения системы. Поэтому очень важно знать — как, почему и где они происходят. Используя JTAG-отладчик Intel, такие ошибки легко обнаружить и добраться до причины их возникновения. Всё это возможно потому, что данный отладчик предоставляет разработчику мощные возможности. Среди них — лёгкий доступ к скомпилированному и исходному коду, просмотр стека вызовов и регистров.

Полезные ссылки


Intel 64 and IA-32 Architectures Software Developer«s Manual
JTAG Tutorial: IEE 1149.x and Software Debug

© Habrahabr.ru