
Из этого материала вы узнаете о том, как отлаживать код и анализировать исключения на уровне ядра 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.

Конфигурация из 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.

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

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

Поиск файла 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 для того, чтобы исключение вызывалось при появлении особых последовательностей символов, вводимых с клавиатуры.

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

Результат вызова макроса BUG(), увеличенный фрагмент копии экрана
Остановка на точке останова Invalid_op
Если установить точку останова в обработчике исключения «Неправильный код операции» или на входе в обработчик исключения, можно увидеть сообщение об исключении, и, в ходе отладки, добраться до места возникновения ошибки.

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

Точка останова в обработчике исключения «Неправильный код операции», увеличенный фрагмент копии экрана
Заключение
Некоторые исключения – это критические ошибки аппаратного и программного обеспечения системы. Поэтому очень важно знать – как, почему и где они происходят. Используя JTAG-отладчик Intel, такие ошибки легко обнаружить и добраться до причины их возникновения. Всё это возможно потому, что данный отладчик предоставляет разработчику мощные возможности. Среди них – лёгкий доступ к скомпилированному и исходному коду, просмотр стека вызовов и регистров.
Полезные ссылки
Intel 64 and IA-32 Architectures Software Developer’s Manual
JTAG Tutorial: IEE 1149.x and Software Debug