Как происходит запись прошивки Android с карты Product


   1       2       3       4       5       6       7       8       9       10   

Для программирования (записи прошивки) устройств на основе SoC Allwinner H616 (H618) с помощью SD-карты используется утилита (точнее, программный пакет) PhoenixCard. Ниже будут показаны некоторые детали и подробности процесса такого программирования.

Исходные данные:

  • PhoenixCard428 на ПК с Windows10

  • ТВ-бокс (приставка) Tanix TX68 на Allwinner H618

  • МикроSD-карта SanDisk 32Gb

  • Файл с образом прошивки Android 12 для Tanix TX68

    Примечание. Конкретная модель приставки указана для примера. На самом деле, всё сказанное ниже будет справедливо и для любой другой приставке на Allwinner H618 (и на каких-то других SoC Allwinner) с точностью до имен разделов и их адресов.


    Cодержимое прошивочной карты Product

    Утилитой PhoenixCard428 на карте создана таблица разделов, состоящая из двух записей, т.е. на карте образовано два раздела. Если такую карту подключить к USB-порту Android-устройства, то консольная команда sgdisk покажет такой результат:


    # sgdisk --print /dev/block/sda
    Disk /dev/block/sda: 62333952 sectors, 29.7 GiB
    Sector size (logical/physical): 512/512 bytes
    Disk identifier (GUID): AB6F3888-569A-4926-9668-80941DCB40BC
    Partition table holds up to 4 entries
    Main partition table begins at sector 73727 and ends at sector 73727
    First usable sector is 73728, last usable sector is 62333949
    Partitions will be aligned on 4-sector boundaries
    Total free space is 3464138 sectors (1.7 GiB)
    
    Number  Start (sector)    End (sector)  Size       Code  Name
       1           73728          139263   32.0 MiB    0700  bootloader_a
       2         3601356        62331903   28.0 GiB    0700  bootloader_b
    

    Примечание. В приведенном выше выводе команды sgdisk для указания на единицу адресации использован термин сектор (sector), доставшийся в наследство от механических накопителей с диском круглой формы. Однако мы будем в описании использовать вместо него термин блок, что более точно соответствует понятию логического блока LBA (Logical block addressing) в современных таблицах разделов GPT. Один блок равен 512 байтам. При чтении можно считать блок и сектор идентичными понятиями (для привыкших к термину сектор).

    В первом разделе bootloader_a размером 32 Mb на карте записан файл boot-resource.fex из образа прошивки, представляющий собой образ диска формата FAT16, cодержащий из самого нужного bootlogo.bmp, который однако в процессе программирования приставки никак не используется (а отображается в виде загрузочного бутлого при старте).

    Сразу после первого раздела находится неразмеченная область, в которую в режиме Product записывается полностью и без каких-либо изменений содержимое файла образа прошивки. Обычный размер которого лежит в пределах 1.5 - 2.0 Гигабайт.

    Адрес, по которому этот образ лежит на карте, определяется по конечному адресу первого раздела (стартовый адрес + длина) в таблице разделов, имеющейся на карте:

  • Для образа Android 12 - это раздел bootloader_a

  • Для образа Android 10 - это раздел bootloader

    В обоих случаях конечный адрес первого раздела (в блоках): 139263 , поэтому IMAGEWTY-образ прошивки на прошивочной карте начинается с блока 139264 (запомним это число).

    Второй раздел bootloader_b (для Android 10 имя раздела env) представляет собой пустой диск, отформатированный в FAT32, который в процессе программирования приставки также не используется. Начальный адрес этого раздела определяется размером записанного на карту IMAGEWTY-образа, а его размер - всё оставшееся на карте место, т.е. размер карты минус стартовый адрес раздела 2.

    Примечание. Из-за необходимости выравнивания границ разделов начало второго раздела не совпадает с концом блоба образа, а может отстоять от него на 16 или 32 Mb (это значение вычисляется в процессе записи карты).

    В сказанном выше легко убедиться, если сохранить три файла командами:

       dd if=/dev/block/sda1 of=part1.bin  conv=fsync
       dd if=/dev/block/sda2 of=part2.bin bs=1M count=16 conv=fsync
       dd if=/dev/block/sda  of=imagewty.bin skip=139264 count=128 conv=fsync

    А затем посмотреть любым HEX-редактором или вьюером содержимое этих файлов. В частности, в самом начале файла imagewty.bin мы увидим заветный заголовок IMAGEWTY:


    Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
    00000000  49 4D 41 47 45 57 54 59 00 03 00 00 60 00 00 00  IMAGEWTY....`...
    00000010  00 00 D0 04 34 02 10 00 00 98 A7 67 00 00 00 00  ..Р.4.....§g....
    00000020  00 04 00 00 34 12 00 00 43 87 00 00 00 01 00 00  ....4...C‡......
    00000030  00 01 00 00 01 00 00 00 00 04 00 00 2D 00 00 00  ............-...
    00000040  00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
    00000050  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
    

    На карте образ записан по адресу 0x4400000 (71303168) в байтах, что соответствует такой арифметике:
    139264 * 512 = 71303168 = 0x4400000


    73728 (36864 Kb - 36 Mb) 37748736 0x2400000 - это начало первого раздела bootloader_a

    Теперь самое важное: в начале прошивочной карты находится неразмеченная область размером 36 Mбайт (73728 блоков). В неё утилитой PhoenixCard записываются загрузчик boot0, а также пакет bootpackage.fex, содержащий несколько блобов: U-Boot, monitor, и дерево устройств (DTB и DTBO)/ (подробности см. Содержимое файла boot_package.php )

    Такое содержимое начальной неразмеченной области прошивочной карты полностью (за исключением одного байта !) совпадает с аналогичным содержимым загрузочной карты, поэтому при подаче питания на прставку с вставленной прошивочной картой стартует обычный режим загрузки, такой-же как и при старте загрузочной карты (или старте прошивки из внутренней памяти). Но эти процессы совпадают только до определенного момента, после которого всё пойдёт не так.


    Чем определяется режим записи прошивки в память приставки (Product)

    Процедура установки прошивки на приставку с прошивочной (Product) карты выполняется запущенным с этой карты загрузчиком U-Boot, режим работы которого определяется значением байта режима работы WORK_MODE в его заголовке, расположенном со смещением 0xe0 = 20 от его начала.

    При записи на карту образа прошивки в режиме Product в начало карты записываются загрузчики Boot0 и U-Boot, при этом в его заголовке устанавливается значение WORK_MODE = 17, которое является признаком работы U-Boot в режиме записи прошивки с карты во внутреннюю eMMC-память приставки.

    В исходных текстах U-Boot имеется файл spare_head.h, содержащий все возможные значения для байта WORK_MODE и соответствующие им режимы работы запущенного U-Boot. Ниже - фрагмент этого файла (перевод коментариев мой, достаточно условный).


    • #define WORK_MODE_BOOT 0x00 // = 0 - обычный режим загрузки (normal boot mode)

    • #define WORK_MODE_USB_PRODUCT 0x10 // = 16 - режим записи прошивки по USB (usb product mode)

    • #define WORK_MODE_CARD_PRODUCT 0x11 // = 17 - режим записи прошивки с карты (card burn mode)

    • #define WORK_MODE_USB_DEBUG 0x12 // = 18 - тестовый режим по протоколу USB efex (some test mode by usb efex protocol)

    • #define WORK_MODE_SPRITE_RECOVERY 0x13 // = 19 - обновление прошивки из внутренней резервной копии (update firmware from internal backup part)

    • #define WORK_MODE_CARD_UPDATE 0x14 // = 20 - обновление прошивки с SD-карты (update firmware from sdcard)

    • #define WORK_MODE_USB_UPDATE 0x20 // = 32 - режим обновления по USB (usb update mode)

    Итак, на загрузочной карте WORK_MODE = 0, на прошивочной карте WORK_MODE = 17

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



  • Этапы записи прошивки с карты Product

    1. Старт вторичного загрузчика SPL (Boot0)

    2. Старт основного загрузчика U-Boot

    3. Проверка и настройка параметров карты (MMC)

    4. Настройка дисплея

    5. Старт записи прошивки в eMMC

    6. Чтение конфигурации

    7. Чтение содержимого файла sunxi_MBR

    8. Очистка разделов флеш-памяти eMMC

    9. Запись содержимого разделов

    10. Запись boot0 и U-Boot, завершение операций


    Ссылки на тексты:

    Заголовочный файл GPT part_efi.h

    Заголовочный файл констант spare_head.h

    Текстовый файл разделов sys_partition.fex

    Текстовый файла sys_config.fex

    Содержимое папки SPRITE в исходных текстах U-Boot

    Тест screen_char

    Исходный текст sunxi_card_sprite_main

    Полный лог записи прошивки Product

       1       2       3       4       5       6       7       8       9       10