Найти в Дзене
mamaich

Яндекс мини 3 про и неудачная попытка переделки на загрузку с SD карты

Оставлю здесь описание своей неудачной попытки доработки Яндекс мини 3 про для удобства изменения его прошивки. Попытка была в отработке идеи переделать устройство на загрузку с SD карты, которую можно легко извлечь, чтобы перепрошить - на ряде других устройств это удавалось сделать. Но из-за особенностей собранного Яндексом u-boot, который настроен загружать ядро операционной системы только с NAND, какой-либо пользы, кроме дополнительного опыта, этот эксперимент не дал. В отличие от следующей, более удачной, попытки, которую опишу в другой раз. Здесь я заодно опишу утилиты, созданные в процессе получения опыта. На Мини 3 про WiFi+BT реализовано чипом aw3155-50r, подключенным к SDIO: Распиновка данного модуля легко гуглится, так что первая мысль была припаяться к его SDIO_CMD и SDIO_CLK, закоротить ноги NAND, чтобы BL1 не смог загрузиться с NAND (я обычно щупом мультиметра корочу между собой две соседние ноги в районе D0..D3 или D4..D7) и посмотреть в логическом анализаторе есть ли обр

Оставлю здесь описание своей неудачной попытки доработки Яндекс мини 3 про для удобства изменения его прошивки. Попытка была в отработке идеи переделать устройство на загрузку с SD карты, которую можно легко извлечь, чтобы перепрошить - на ряде других устройств это удавалось сделать. Но из-за особенностей собранного Яндексом u-boot, который настроен загружать ядро операционной системы только с NAND, какой-либо пользы, кроме дополнительного опыта, этот эксперимент не дал. В отличие от следующей, более удачной, попытки, которую опишу в другой раз.

Здесь я заодно опишу утилиты, созданные в процессе получения опыта.

На Мини 3 про WiFi+BT реализовано чипом aw3155-50r, подключенным к SDIO:

кроме CMD и CLK я еще припаял землю, питание и D0
кроме CMD и CLK я еще припаял землю, питание и D0

Распиновка данного модуля легко гуглится, так что первая мысль была припаяться к его SDIO_CMD и SDIO_CLK, закоротить ноги NAND, чтобы BL1 не смог загрузиться с NAND (я обычно щупом мультиметра корочу между собой две соседние ноги в районе D0..D3 или D4..D7) и посмотреть в логическом анализаторе есть ли обращения к с этой SD. Обращенийй от BL1 не было. Почему - я не разобрался. Возможно, для загрузки требуется поиграть с пином Card Detect для имитации "вставленности" SD карты или полностью выпаять модуль, чтобы ничего на нем не мешало.

Другая идея была подсказана angellfear - выпаять NAND и заставить устройство загружаться с eMMC. А так как eMMC и SD по сути практически идентичный протокол, то вместо eMMC можно запаять SD-card ридер.

На прошлых процессорах Amlogic (для которых доступна документация) GPIO выводы для подключения NAND и для подключения eMMC были совмещены. То есть D0..D7 NAND совпадали с D0..D7 eMMC, а CMD и CLK были на двух управляющих ногах NAND (причем на разных процессорах эти ноги были разными). Так как распиновки процессора A113L2 в публичном доступе нет, то пришлось заняться перебором. Выяснилось, что CMD для eMMC это та же нога, что NAND_nRE (нога №8 микросхемы NAND), а CLK - это NAND_nWE (нога №18). Так что я выпаял NAND и припаял кард ридер:

-2

В качестве проводов хорошо подошел 80-пиновый шлейф от IDE диска - расстояние между его жилами почти идеально ложится для пайки на площадки.
Кардридер должен быть самый простой - без подтягивающих резисторов!
SD карту я тоже взял старую на 4 Гб.

Отмечу, что встроенный в процессор загрузчик (BL1) поддерживает загрузку с eMMC только в 4-битном режиме, так что требуется запаять D0..D3. Одного только D0 для загрузки недостаточно.

Для информации: подтягивание ног D1..D5 через резистор (от 4.7К до 10К) к земле меняет порядок загрузки. Это я случайно обнаружил взяв сперва кардридер с резисторами подтяжки. Таблицу приоритетов загрузки я не составлял - желающие могут это сделать самостоятельно. По умолчанию (без резисторов) порядок такой: NAND; eMMC; SPINAND; SD; USB.

После завершения пайки - требуется подготовить образ SD карты.

Сперва читаем NAND программатором, в моем случае это дешевый XGecu T48 с кареткой под TSOP48 NAND (ADP_F48_EX-2).

-3

Владельцам программатора UFPI утилиты, описанные далее в статье бесполезны - у них функционал по внесению изменений в файловую систему и пересчет ECC встроен. Но так как мой программатор этого функционала не имеет - пришлось разработать свои инструменты и я опишу как ими пользоваться в этой и в следующей статьях.

Ключевое отличие NAND и eMMC памяти - в ненадежности NAND, с которой разработчикам прошивки устройств приходится справляться самостоятельно. В каждой странице NAND памяти может присутствовать до нескольких ошибочно записанных/читаемых битов, и исправление этих битов ложится на программный код. Для хранения информации, необходимой для проверки целостности данных и их восстановления в каждой странице NAND памяти присутствуют дополнительные байты Out Of Band (OOB) данных:

-4

В нашем случае размер страницы 4352 байта. Страница состоит из блоков по 528 байт (512 байт данные пользователя, 2 байта вспомогательные данные и 14 байт ЕСС). В конце страницы идут 128 байт spare данных (обычно FF). Вспомогательные данные используются для отметки плохих блоков, блоков, принадлежащих загрузчикам и FIP - подробности есть где-то в исходниках, но я в них не вникал.

После считывания дампа NAND требуется найти и исправить значения всех ошибочных битов (их на весь дамп достаточно много). С кодом мне помог Allsafe - поделился алгоритмом расчета ECC BCH, использующимся у Amlogic для исправления ошибок в NAND (до 8 битов на страницу). Далее с помощью Grok была написана утилита, восстанавливающая по ЕСС правильные данные во всем дампе.

Использование утилиты примерно такое:

./ecc_fix fixdata TC58NVG2S0HTAI0@TSOP48.BIN TC58NVG2S0HTA00@TSOP48-fixed.bin

на выходе из считанного дампа TC58NVG2S0HTAI0@TSOP48.BIN получаем исправленный дамп TC58NVG2S0HTA00@TSOP48-fixed.bin

Следующее действие, необходимое для работы с прошивкой - удалить из дампа все OOB данные. Для этого я с помощью Grok написал утилиту:

./file_skip ./TC58NVG2S0HTA00@TSOP48-fixed.bin out.bin

Получаем файл out.bin с чистым образом дампа. Точнее, не совсем чистым - file_skip не умеет пропускать плохие блоки (а вот программатор UFPI - умеет). В моем случае это был не критично, так как бэды моей платы попали куда-то в неиспользуемое место раздела data.

Далее из файла out.bin формата NAND требуется сделать прошивку под формат eMMC. Можно посмотреть на лог загрузки устройства с NAND и увидеть такие строки:

BL2E 01000000 00040000
BL2X 01200000 00040000
DDRFIP 01400000 00040000
DEVFIP 01600000 00300000

это смещения и размеры разделов BL. Для eMMC смещения и размеры должны быть такими:

BL2E 00033200 00013000
BL2X 00046200 00011000
DDRFIP 00057200 00040000
DEVFIP 00097200 00300000

В логе нет адресов начала и размера раздела BB1ST, который загружается самым первым. В NAND его первая копия расположена по смещению 0x1000, в eMMC по смещению 0x200. Размер = 0x32800 байт.

Можно взять эти разделы из NAND и положить по соответствующим адресам eMMC, а можно поступить проще.

В образе прошивки устройств Amlogic есть раздел aml_sysrecovery, расположенный по смещениям 0x2400000-0xa480000:

-5

Есть исходник aml-upgrade-package-extract для разбора aml_sysrecovery на части (изначально он родом отсюда, но ссылка временами недоступна). С помощью этой утилиты разбираем раздел и берем оттуда файл boot.PARTITION. Это - образ загрузочных разделов со смещениями, как требуется для eMMC, только с отрезанными 0x200 нулевыми байтами в начале файла.

видна сигнатура @ML и остальное начало совпадает с содержимым NAND по смещению 0x1000
видна сигнатура @ML и остальное начало совпадает с содержимым NAND по смещению 0x1000

Записываем содержимое boot.PARTITION на SD карту начиная со смещения 0x200 и получаем загрузочную SDшку, которая вполне успешно стартует.:

-7

Однако дальше загрузка не идет - u-boot падает внутри выполнения команды "setenv bootargs ...":

как я понял что это "setenv bootargs" - из анализа стека вызовов в IDA
как я понял что это "setenv bootargs" - из анализа стека вызовов в IDA

Можно взять более свежий FIP (и соответственно u-boot) из любого обновления, он не падает, но и не пытается грузить ядро Linux с SD карты - я проверил логическим анализатором к каким адресам SD карты идет обращение. Обращения заканчиваются на чтении FIP и, похоже, далее u-boot пытается продолжить загрузку с NAND. А если нажимать на Enter - то выскакивает кролик.

Кстати, про FIP. Раздел aml_sysrecovery содержит в себе два интересных файла: UBOOT.USB и UBOOT_ENC.USB. Это также образы загрузчиков. Файл UBOOT_ENC.USB содержит подписанные разделы, но не верным сертификатом из-за чего получаем ошибку при загрузке, а файл UBOOT.USB содержит в себе FIP, в котором присутствуют незашифрованные BL30 (это прошивка для RISC ядра always-on CPU) и BL33 (это u-boot). U-Boot сжат алгоритмом LZ4, так что перед загрузкой в IDA (адрес загрузки ставьте 0) его надо распаковать.

Адрес начала FIP в файле UBOOT.USB == 0x97000 (на 0x200 меньше чем адрес начала DEVFIP в логе - думаю, очевидно почему), длина те же 0x300000. Для того, чтобы разобрать FIP на части можно использовать питоновский скрипт отсюда. Файл 00_00008000_9766fd3d89bee849ae5d78a140608213 - BL30, файл 04_000f4000_d6d0eea7fcead54b97829934f234b6e4 - сжатый BL33.

Как распаковать LZ4 - я выложил свой исходник (написанный с помощью Grok, так как я вконец обленился). Использовать так:

./unpack_lz4c ./04_000f4000_d6d0eea7fcead54b97829934f234b6e4 ./u-boot.bin

После распаковки можно загрузить u-boot.bin в IDA. Процессор - 64-битный ARM, адрес загрузки ставьте 0.