2015-02-02 2 views
2

В ядре Linux, когда срабатывает контрольная точка, зарегистрированная с помощью register_wide_hw_breakpoint, обработчик обратного вызова бесконечно работает до тех пор, пока точка останова не будет зарегистрирована.register_wide_hw_breakpoint постоянно вызывает обратный вызов обработчика

Background: Чтобы проверить драйвер для некоторых аппаратных средств, которые мы создаем, я пишу второй модуль ядра, который эмулирует аппаратный интерфейс. Мое намерение состоит в том, чтобы установить точку наблюдения в ячейке памяти, которая в аппаратном обеспечении будет управляющим регистром, так что запись в этот «регистр» может инициировать операцию с помощью драйвера эмулятора.

См. here for a complete sample. я поставил точку останова следующим образом:

hw_breakpoint_init(&attr); 
attr.bp_addr = kallsyms_lookup_name("test_value"); 
attr.bp_len = HW_BREAKPOINT_LEN_4; 
attr.bp_type = HW_BREAKPOINT_W; 
test_hbp = register_wide_hw_breakpoint(&attr, test_hbp_handler, NULL); 

но когда test_value записывается, обратный вызов (test_hbp_handler) запускается непрерывно без контроля когда-либо вернуться к коду, который собирался написать test_value.

1) Что я должен делать по-другому, чтобы это работало должным образом (верните выполнение кода, который вызвал точку останова)?

2) Как записать значение, которое записывалось в ячейку памяти?

В случае, если это имеет значение: $ uname -a Linux socfpga-cyclone5 3.10.37-ltsi-rt37-05714-ge4ee387 #1 SMP PREEMPT RT Mon Jan 5 17:51:35 UTC 2015 armv7l GNU/Linux

+0

1. Знаете ли вы, какие инструкции запускают HW BP каждый раз? Вы можете использовать% pS при печати IP для получения дополнительной информации. – Eugene

+0

2. Что касается второго вопроса - не уверен в ARM, но я работаю с HW BP в проекте на x86 и могу использовать декодер команд, ядро ​​должно, ну, декодировать insn, пытающийся получить доступ к памяти. Затем можно найти выражение, которое оно записывает в эту память, то есть немедленное значение или выражение с регистрами. Его можно оценить, доступны значения регистров. Возможно, что-то подобное доступно и на ARM. Наверное, реализация Kprobes может дать некоторые намеки. – Eugene

+0

arch/arm/kernel/kprobes-common.c может быть полезно просмотреть. – Eugene

ответ

2

Это дизайн. Когда удаляется точка наблюдения аппаратного обеспечения ARM, она генерирует исключение Data Abort. В ARM исключения исключений данных запускают до инструкция, которая запускает их завершение . Это означает, что в обработчике исключений регистры и места памяти, на которые влияет команда, по-прежнему сохраняют свои старые значения (или, в некоторых случаях, неопределенные значения). Таким образом, когда обработчик заканчивается, он должен повторить отмененную команду, чтобы прерванная программа выполнялась по назначению . Если контрольная точка все еще установлена ​​при возврате обработчика, команда снова запустит ее. Это вызывает цикл, который вы видите.

Чтобы обойти это, отладчики пользовательского пространства, такие как GDB, на один шаг над любой инструкцией, которая удаляет точку наблюдения с этой точкой наблюдения, перед возобновлением выполнения. Однако базовый API-интерфейс ядра просто раскрывает поведение аппаратного контроля. Поскольку вы используете API ядра, для обработчика событий вы должны следить за тем, чтобы точка наблюдения не срабатывала по повторной инструкции.

[Код точки наблюдения ARM в ядре фактически поддерживает автоматическую одношаговую, но только при очень специфических условиях. А именно, это требует: 1) что обработчик событий не зарегистрирован в точке наблюдения, 2) что точка наблюдения находится в пользовательском пространстве и 3) что точка наблюдения не связана с конкретным процессором. Поскольку ваш случай использование нарушает по меньшей мере, (1) и (2), вы должны найти другое решение.]

К сожалению, на ARM, нет безопасного способа держать точку наблюдения включено, не вызывая петлю. Режим точки останова, используемый GDB для одношаговых программ, «несоответствие команд», генерирует поведение UNPREDICTABLE при использовании в режиме ядра . Лучшее, что вы можете сделать, это отключить точку наблюдения в вашем обработчике, а затем установить стандартную точку останова, чтобы снова включить ее в команде, которую, как вы знаете, будут выполняться вскоре после этого.

Для вашего драйвера эмуляции MMIO точки наблюдения, вероятно, не являются ответом.В дополнение к упомянутым вопросам большинство ядер ARM имеют очень мало регистраторов точек наблюдения, поэтому решение не будет масштабироваться. Боюсь, я недостаточно знаком с моделью памяти ARM, чтобы предложить альтернативный подход. Тем не менее, Linux existing code для эмуляции IO с отображением памяти для виртуальных машин может быть хорошим местом для запуска.


Есть два типа ABORt данных исключений, синхронных и асинхронных, и это осталось в реализации, чтобы решить, какой из них генерирует точка наблюдения. Я описываю поведение синхронных исключений в этом ответе, потому что именно это вызовет проблему, с которой вы столкнулись.

Справочное руководство по архитектуре ARMv7-A/R, B1.9.8, «Исключение данных об исключении».

Linux Kernel v4.6, arch/arm/kernel/hw_breakpoint.c, lines 634-661.

Справочное руководство по архитектуре ARMv7-A/R, C3.3.3, «НЕПРЕРЫВНЫЕ случаи, когда выбран режим отладки Monitor».