Добавить в корзинуПозвонить
Найти в Дзене
mamaich

Отключаем ARM TBB и загружаем своё ядро на Яндекс ТВ Станции

Ранее я описал, как сдампить ядро Android в расшифрованном виде. Полученный образ ядра следует распаковать с помощью Android Image Kitchen. В папке split_img берем файл "kernel_dump.img-kernel" - это запакованное ядро Android (так как файл образа со сдампленным ядром Android у меня назывался kernel_dump.vhd, то все файлы начинаются с kernel_dump). Ядро Android (файл kernel_dump.img-kernel) следует распаковать и проверить, что распакованный файл - действительно ядро: Ramdisk, полученный из Kitchen не берём - там только первая часть, содержащая init и пустые папки. С таким ядром система не загрузится. Как сдампить правильный ramdisk я писал в конце той же статьи. Если открыть полученный по статье дамп initrd в 16-ричном редакторе и сделать поиск строки "TRAILER!!!" - будет видно, что после нее идет начало еще одного cpio образа: Во второй части лежат драйвера. Судя по документации, ramdisk может быть разбит больше чем на 2 части. Для тестовой загрузки можно взять файл ramdisk в том вид

Ранее я описал, как сдампить ядро Android в расшифрованном виде.

Полученный образ ядра следует распаковать с помощью Android Image Kitchen. В папке split_img берем файл "kernel_dump.img-kernel" - это запакованное ядро Android (так как файл образа со сдампленным ядром Android у меня назывался kernel_dump.vhd, то все файлы начинаются с kernel_dump).

Ядро Android (файл kernel_dump.img-kernel) следует распаковать и проверить, что распакованный файл - действительно ядро:

Ramdisk, полученный из Kitchen не берём - там только первая часть, содержащая init и пустые папки. С таким ядром система не загрузится. Как сдампить правильный ramdisk я писал в конце той же статьи.

Если открыть полученный по статье дамп initrd в 16-ричном редакторе и сделать поиск строки "TRAILER!!!" - будет видно, что после нее идет начало еще одного cpio образа:

-2

Во второй части лежат драйвера. Судя по документации, ramdisk может быть разбит больше чем на 2 части.

Для тестовой загрузки можно взять файл ramdisk в том виде, как он был сдамплен ранее. В случае необходимости подмены в нём init своим (например, как делает magisk) - лучше вручную объединить оба образа в один. Для этого просто вырезаем второй образ от "070701..." до конца файла (там мы увидим еще один "TRAILER!!!") и распаковываем в ту же папку, куда распаковали первый образ.

Здесь я опишу тестовую загрузку в оригинальное (свежесдампленное) ядро Android, с оригинальным ramdisk и DTB. Для этого нужна флешка с FAT, на которой записаны файлы ядра (файл с именем Image), ramdisk (uInitrd), dtb (dtb) и скрипт (aml_autoscript).

Загрузка ядра с USB производится такими командами, которые надо добавить в aml_autoscript или запустить вручную из интерактивного u-boot:

mw.l 0x1ffffc0 0 0x10;mw.l 0x1ffffc0 0x56190527;mw.l 0x1ffffcc 0x00000002;mw.l 0x1ffffd0 0x00000002;mw.l 0x1ffffd4 0x00000002;mw.l 0x1ffffdc 0x00021605;
fatload usb 0:0 0x02000000 Image
crc32 0x2000000 0x2000000 0x1ffffd8
crc32 0x1ffffc0 0x0000040 0x1ffffc4
md.b 0x1ffffc0 0x40
mw.l 0x00000000BF5DCB9C 0xd2800000
mw.l 0x00000000BF5DCBA0 0xd65f03c0
setenv bootargs "init=/init rdinit=/myinit console=ttyS0,115200 no_console_suspend earlycon=aml-uart,0xfe07a000 scramble_reg=0xfe02e030 ramoops.pstore_en=1 ramoops.record_size=0x8000 ramoops.console_size=0x4000 loop.max_part=4 logo=osd0,loaded,0x00300000 powermode=last vout=2160p60hz,enable panel_name=vbyone_1region panel_type=lvds_1 lcd_ctrl=0x000000a2 lcd_debug=0x00000000 hdmimode=1080p60hz outputmode=2160p60hz osd_reverse=n video_reverse=0 irq_check_en=0 "
setenv bootargs ${bootargs} "androidboot.selinux=permissive androidboot.firstboot=1 jtag=disable disable_ir=0 vendor.init_screen_mode=on androidboot.bootloader=01.01.250408.101157 androidboot.hardware=amlogic mac=${mac} androidboot.mac=${mac} androidboot.deviceid=${serial} androidboot.serialno=${serial} androidboot.subscription_mode=unset androidboot.hardware.amlogic_dt_id=t3_magritte_hvt androidboot.hardware.revision=1 "
setenv bootargs ${bootargs} "androidboot.wificountrycode=US ffv_freeze=off androidboot.qc_mode=0 androidboot.rh_unlock=1 androidboot.adb_enable=1 androidboot.force_normal_boot=1 otg_device=0 reboot_mode=normal"
fatload usb 0:0 0x13000000 uInitrd
fatload usb 0:0 0x04000000 dtb
echo Starting kernel...
bootm 0x1ffffc0 0x13000000 0x04000000

Конкретные параметры bootargs лучше подсмотреть на своем устройстве.

Так как на u-boot с процессором T3 программисты из Amlogic убрали поддержку команды "boota", приходится использовать оставшуюся доступной команду "bootm".

Команда bootm требует наличие заголовка перед образом Android (желающие могут посмотреть его в исходниках u-boot) - так что первые строки подготавливают 64-байтный заголовок по адресу 0x1ffffc0, загружают сразу после него ядро Android (0x02000000), пересчитывают CRC. Эти команды универсальные и не зависят от версии u-boot или устройства, и подсмотрел я их в amlogic-bootscripts-Armbian (файл gxl-fixup). Я только добавил автоматический расчет CRC.

Далее две команды mw.l выключают TBB.

Если не отключать TBB, при при загрузке мы получим ошибку "aml log : Sig Check -2":

-3

Посмотрев в исходник команды bootm для процессоров Amlogic, видим в разных местах проверку "IS_FEAT_BOOT_VERIFY()" и после нее код расшифровки/проверки подписи:

-4

Если IS_FEAT_BOOT_VERIFY() вернет 0, то u-boot загрузит файлы без проверки подписи - тем самым мы отключим TBB.

IS_FEAT_BOOT_VERIFY берет данные из eFuse. Нам, к счастью, не требуется перепрограммировать фьюзы - достаточно пропатчить данную функцию, чтобы она всегда возвращала 0. Функция выглядит так:

-5

Меняем её начало на "MOV X0,#0" (0xd2800000) и "RET" (0xd65f03c0).

Далее в скрипте всё стандартно, заполняется bootargs, грузится initrd и dtb и ядро запускается командой bootm.

Отмечу, что u-boot в конец строки bootargs допишет информацию из VBMETA, так что если внести изменения в раздел super (он содержит system, vendor, product, ...) или другие подписанные, то система не загрузится. Поэтому magisk, да и я в своих поделках для устройств под новыми Андроид, изменяем только initrd и ядро (файл Image), содержимое которых никак не проверяется.

В ядре лучше всего начать с патча функции avc_denied, как я писал тут (в статье патчится функция в памяти - но ничто не мешает провести такие же изменения в файле Image на диске). Следом за ней - запатчить функцию sel_read_enforce, чтобы прочитав файл "/sys/fs/selinux/enforce" стать рутом (в патч лучше добавить проверку на "магическое значение" в параметре количества считываемых байт, чтобы не сломать процесс загрузки Андроид).

Какие именно изменения я вношу в свой ramdisk и что они дают - возможно, опишу как-нибудь в будущем.