Как отлаживать Android ядро без UART, JTAG и прочих

в 19:05, , рубрики: android, C, debug, jtag, kmsg, last_kmsg, linux, LLCON, Qualcomm, uart, Разработка под android, Разработка под Linux, системное программирование

Довольно часто разработчики ядер под Android устройства сталкиваются с тем, что собранное из исходников ядро просто напросто не работает. И при этом часто разработчик, собравший ядро, не имеет никаких специальных средств для отладки. В данной ситуации без kmsg логов довольно трудно что либо сделать. Конечно же в Linux ядре уже имеется несколько способов копирования содержимого kmsg буфера в специальную область памяти, но если вам интересно узнать ещё об одном способе, то прошу под кат.

Недавно я уже описывал одну из возможностей модуля LLCON, которая заключалась в отображении kmsg логов на дисплее Android устройства. Теперь настало время описать похожий механизм копирования kmsg логов, т.к. отображение логов на экране не очень удобно для поиска всевозможных ошибок.

Для начала стоит отметить тот факт, что в большинстве случаев оперативная память Android устройства не очищается при рестарте SoC. Эту особенность использует механизм, который обеспечивает появление файла /proc/last_kmsg. Но порой для принудительного рестарта SoC приходится долго удерживать кнопку Power, что влечёт за собой либо полное, либо частичное изменение содержимого оперативной памяти. В данном случае я рекомендую подключать устройство к ПК через USB-кабель, что бы содержимое оперативной памяти не изменялось (по крайней мере на моём устройстве это работает).

Поэтому при старте первым же делом тестовое ядро должно зарезервировать некоторую область оперативной памяти для дублирования в оную содержимого kmsg буфера. Я обычно под это дело выделяю 1 MiB памяти, а в качестве физического адреса использую 0x7f200000, т.к. на моём устройстве установлено 2 GiB SDRAM.

Т.е. на своём Android устройстве для включения данного функционала я в командную строку ядра добавляю дополнительный параметр:

llcondmp=0x7f200000,0x100000

Пример добавления параметра llcondmp в BoardConfig

BOARD_KERNEL_CMDLINE := androidboot.hardware=qcom
BOARD_KERNEL_CMDLINE += androidboot.selinux=permissive
BOARD_KERNEL_CMDLINE += msm_rtb.filter=0x37
BOARD_KERNEL_CMDLINE += user_debug=31 debug ignore_loglevel
BOARD_KERNEL_CMDLINE += llcondmp=0x7f200000,0x100000

Тестовое ядро, в котором имеется модуль LLCON, при запуске должно обработать данный параметр и зарезервировать указанную область оперативной памяти. При этом будет включён механизм, который будет дублировать kmsg логи и в эту специально подготовленную область памяти. Причём данное дублирование будет осуществляться внутри вызова функции printk (т.е. моментально и прозрачно). Данное обстоятельство позволяет получать kmsg логи даже при экстренном рестарте SoC тестируемого устройства.

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

Для того, что бы используемое в TWRP ядро зарезервировало в оперативной памяти участок 0x7f200000...0x7f2FFFFF, нужно отредактировать DeviceTree этого ядра. Сам процесс редактирования DeviceTree требует написания отдельной статьи, поэтому я всего лишь приведу само изменение в dts-файле:

/dts-v1/;
/memreserve/ 0x7f200000 0x100000;  /* добавленная строка */
/include/ "msm8226-v2.dtsi"
/include/ "msm8226-qrd.dtsi"

Но на этом переделка TWRP не завершена. Нужно в ramdisk добавить утилиту viewmem, которая позволяет сбрасывать содержимое физической памяти на диск. Исходники данной утилиты можно скачать тут: viewmem.

Где можно взять готовый бинарь viewmem

Если сборкой TWRP из исходников замарачиваться совсем не хочется, то советую исходники viewmem добавить в тот же проект, который используется для сборки тестового ядра. И уже готовый бинарный файл viewmem просто встроить в нужный образ TWRP.

После подготовки специальной версии TWRP оный нужно залить в устройство. Причём для тестирования кастомных ядер этот TWRP я советую заливать в раздел «boot», т.к. именно на его содержимое бутлоадер передаёт управление по-умолчанию. Описывать способы заливки образов разделов здесь не стану, что бы совсем не выбивается из тематики данной публикации.

Для начала стоит опробовать работу установленного в устройство специальной версии TWRP. Можно даже проверить работу утилиты viewmem (см. ниже пример использования). Так же замечу, что для рестарта этого TWRP следует в разделе меню «Restart» выбирать пункт «System», т.к. TWRP у нас находится в разделе «boot».

Теперь у нас есть специальный TWRP и тестовое ядро с модулем LLCON, которое либо зависает, либо заставляет SoC ребутиться. И этого вполне достаточно для поиска причин такого поведения тестового ядра. Образ тестируемого ядра я рекомендую заливать в раздел «recovery». Поэтому для начала тестирования проблемного ядра следует в разделе меню «Restart» выбрать пункт «Recovery». Это будет означать то, что при перезагрузке устройства бутлоадер передаст управление на содержимое раздела «recovery». Далее следует дождаться возникновения ошибки в тестируемом ядре. Если ошибка сама вызывает рестарт SoC, то делать ничего не нужно, т.к. должен автоматически загрузиться ранее подготовленный TWRP. Если же ошибка вызывает зависание, то зажмите кнопку Power и дождитесь хардварного рестарта (главное не забудьте про USB-кабель).

Загрузившись в TWRP нужно первым же делом при помощи ADB-соединения скопировать kmsg логи из памяти на диск:

adb shell
viewmem 0x7f200000 0x100000 > /sdcard/kmsg_llcon.txt
exit

Теперь нужно с SD-карты скопировать файл kmsg_llcon.txt и начать изучать его содержимое.

Данный метод отладки я использовал уже трижды:

  • создание кастомного ядра версии 3.4 для устройства Innos D10F (2014 год);
  • создание кастомного ядра версии 3.4 для устройства Innos D9 (2015 год);
  • создание кастомного ядра версии 3.10 для устройства Innos D10F (текущий проект).

Так что при разработке Android ядер можно вполне обойтись и без UART, JTAG, EmbeddedICE DCC и прочих средств, использующихся для отладки.

Примечание: исходники модуля LLCON ищите в моей прошлой публикации "Заменяем бут-анимацию Android устройства на мелькающие логи Linux ядра".

Автор: acDev

Источник

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


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