Pull to refresh

GNU/Linux и устройство на Rockchip 2918

Reading time26 min
Views48K
Сначала немного предыстории. Небольшое продолжение истории с медиаплеером GV2B, описанным мной ранее ту/т. Напомню, что изначально бокс покупался не как Android приставка к телевизору, а как более мощная замена Raspberry Pi, на который я оставил заявку ещё в апреле, но приедет который только в августе. А GV2B оказался у меня в руках через 8 дней после заказа, всего за $100 и с полным комплектом кабелей (что всего на $5 дороже, чем комплект Raspberry Pi с зарядкой, шнурами и корпусом).
Успокою злопыхателей из моего предыдущего поста, что Youtube и другие приложения, установленные с Play, заработали замечательно, и больше никаких недостатков у устройства обнаружено не было.

Совсем недавно появилось пара топиков, в которых рассказывалось, как на ARM устройства удалось поставить Puppy Linux, Arch Linux и Ubuntu. Это уникальная особенность Allwinner A10, недооценить которую тяжело, но всё-таки система физически запускается с SD карты, а не встроенного флеша. Я начал активнее работать над вопросом, и наткнулся аж на три способа прошить что-либо во флеш память устройства, что обнадёживает и, возможно открывает лазейку для заливки туда полноценного GNU/Linux. Самонадеянно замечу, что это уже следующий шаг за банальным запуском чуть допиленного образа с SD карты.

Цель


— Установить на устройство ядро Linux. Желательно самое новое. Либо самое новое из тех, которое содержит все драйвера, специфические для устройства;
— Поставить GNU;
— Поставить окружение рабочего стола;
— Сделать резервную копию, чтобы устройство можно было вернуть в изначальное состояние, если что пойдёт не так;
— Хорошенько повеселиться со сложной задачей (сравнимо с установкой первых версий USB загрузчиков на Wii и прохождению NetHack или Dwarf Fortress).

Средства


Устройство GV-2B от неизвестного китайского производителя, на базе Rockchip 2918 (сокращённо RK29) (CPU ARM Cortex A8 1ГГц + GPU Vivante GC800 600МГц), с 4ГБ флеш памяти, 512МБ оперативной памяти и неплохим количеством разьёмов.
SD карта 16ГБ class 10.
PC с Arch Linux.
Клавиатура.
Монитор.
Шнур HDMI-DVI для подключения монитора.
Куча USB шнуров, переходников итп.

Предостережение и самобичевание


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

Выбор устройства


В модельном ряду G около двадцати разных устройств, на разных процессорах, с разным количеством разъёмов, но примерно одинакового функционала.

Поначалу я убивался по поводу того, что не взял устройство на Allwinner A10, но после прочтения нескольких отзывов по поводу открытости исходников ядра к нему, я понял, что с Rockchip ситуация не намного хуже.

Был вариант заказать устройство того же модельного ряда, но уже с Cortex A9, а именно AmLogic 8726-M, но каких-то чрезвычаных преимуществ перед Rockchip 2918 он не имеет, а с иходным кодом для последних чипов, судя по сайту AmLogic, всё тоже печально.

Методы


Итак, было найдено три способа обновить прошивку устройства (содержание той самой 4хгигабайтной флеш памяти).

Первый — от производителя, использующего одну из OEM моделей линейки GV, не cработал, да оно и хорошо, потому что их прошивка предназначается для немного другого устройства, к которого три USB порта, и разница между ними настолько серьёзна, что обычно прошивка оборачивается превращением устройства в кирпич.

Остались два. Второй, от хакера с AndroidForums, заключается в том, что нужно наживать на дополнительную, вторую кнопку reset, находящуюся внутри коробки, удерживая её держать кнопку включения в течение нескольких секунд. Этот способ открыл интересные особенности, а именно меню Android system recovery utility v1.3.37 (очевидно 1337), предлагающее на выбор:
— Reboot system now
— Factory reset
— SYSTEM recover
— Update from SDCARD
— Update from uDisk
— Factory test



К огромному сожалению, клавиатура, будучи подключенной к устройству, и отлично работающая уже после загрузки Android, на меню system recovery никакого воздействия не оказывала, а из трёх имеющихся на плате кнопок (power, reset, ещё reset) на меню действовала толко одна — первый reset, который то ли приводил он к выбору активного по умолчанию пункта Reboot system now, а то ли и просто работал по прямому назначению. Остальные кнопки курсор, к сожалению, не двигали. Способ заключался именно в том, чтобы залить прошивку с карты памяти SD, что никак и не получалось.

Отформатировав SD карту в fat32, я залил на неё с трудом скачанный с файлопомойки (боже, неужели они не слышали о Dropbox'е?) скачанный апдейт для Android'а. При нормальной загрузке Android ругался на то, что на SD карте находится неправильный update.img. Но заливать его я всё равно не спешил, ведь резервные копии делают не только трусы, а на форумах зачастую соощалось, что заливка того или иного update.img, который у одного автора заработал, на аналогичном устройстве приводило к превращению в кирпич у другого автора.

Третий сынспособ оказался ближе к тому, что я собирался сделать. Заключался он в подключении устройства к компьютеру с помощью USB шнура.

Поначалу очень смущало то, что в режиме system recovery устройство никак не определялось с компьютера, несмотря на то, что все нужные провода я подключал куда надо (и даже куда не надо, направляя встречное питание 4.57В и 5.08В по USB, что по счастью не обернулось никакими последствиями). Как позже выяснилось, так и должно быть, ибо протокол у них там свой, и разница с подключением внешних носителей существенна.

Под Windows обнаружилась программа Rockchip Flasher tool, которую язык никак не поворачивается назвать замечательной, потому что сделана она ужасно и единственное, что умеет делать — это прошивать новые update.img. Но мне нужно было не только прошить, но и скачать имеющуюся, на случай того, если вдруг что-то пойдёт не так, поэтому от творчества китайских программистов пришлось отказаться.

С ножками, кстати, нужно быть осторожнее.


Резервное копирование


Хочется сохранить всё, что хранится во флеш памяти для возможности восстановления всего к изначальному варианту, если что пойдёт не так. Для этого существует несолько разных методов.

Titanium Backup. Android приложение, с помощью которого можно сделать снимок системных разделов и скопировать его на SD карту. Всё бы хорошо, но устройство для этого необходимо рутировать (получить административные привилении). Для того, чтобы рутировать устройство на Android 2.3.1, Universal Androot уже не подходит, и его автор предлагает на выбор воспользоваться Unrevoked, который подходит только для телефонов HTC, или SuperOneClick, который вроде бы всем хорош, но для того, чтобы зарутировать устройство требует его подключения шнуром к компьютеру с Windows. Всё бы и неплохо, но он скачивает прошивку, добавляет туда какие-то файлы и заливает обратно. Менять прошивку для того, чтобы сделать её резервную копию — это маразм.

Оставалось воспользоватся Android Debug Bridge из Android SDK, которая не факт что заработала бы с этим конкретным устройством, и тянущая за собой немалое количество зависимостей, которых мне совсем не хотелось. Ко всему прочему собирать всё это нужно было из исходников (читай AUR для Arch Linux).

Уже было взгрустнув, я вдруг обнаружил замечательную утилиту RK29kitchen, аннонсированную здесь которая, судя по описанию, впитала в себя ряд других не менее замечательных утилит от авторов, которые разобрали хитрый протокол общения устройств по USB, и чуть менее хитрый файл с таблицей разделов.

Запуск


Оказалось не так просто. Оказывается, устройство должно быть не в system recovery режиме, а в выключенном состоянии, но обязательно с подключенным питанием. Проблема в том, что оно пытается включиться, как только чуствует, что поключено по USB. Но с этим можно совладать. Удерживая обе кнопки reset 5 секунд, отпускаю сначала вненшюю, а через 3 секунды и внутреннюю. Запускаю и стараюсь быть терпеливым.
$ ./flashdump.sh
Check that your tablet is in the firmware flash mode and connected to computer

rkflashtool: info: interface claimed
rkflashtool: info: reading flash memory at offset 0x00000100
unpacking...OK
Dumping misc (rkflashtool29 r 0x00002000 0x00002000 )
Dumping kernel (rkflashtool29 r 0x00004000 0x00004000 )
Dumping boot (rkflashtool29 r 0x00008000 0x00002000 )
Dumping recovery (rkflashtool29 r 0x0000a000 0x00004000 )
Dumping system (rkflashtool29 r 0x0000e000 0x00080000 )
Dumping backup (rkflashtool29 r 0x0008e000 0x00082000 )

Немного смущает то, что в исходнике flashdump'а написано:
rkflashtool29 r 0 0x200

А в выводе:
reading flash memory at offset 0x00000100

Не совсем понятно, с какого же именно смещения читается parm.img.

Итак, 5-10 минут и золотой ключик у меня есть образа флеш памяти целиком и по отдельности всех разделов:
$ ls -l flashdump/Image/
   4194304 Jun 29 18:15 boot.img
   8388608 Jun 29 18:15 kernel.img
   4194304 Jun 29 18:14 misc.img
   8388608 Jun 29 18:16 recovery.img
 268435456 Jun 29 18:18 system.img

$ ls -l flashdump
 272629760 Jun 29 18:21 backup.img
      4096 Jun 29 18:16 Image
       583 Jun 29 18:13 parameter
    262144 Jun 29 18:13 parm.img

Что же произошло? Если покопаться на форумах и в исходниках RK29kitchen, становится понятно, что я только что прочёл содержание флеш памяти устройства, начиная с таблицы разделов, которую нам разобрали по полочкам и записали в текстовом файле parameter, и используя её, записали по раздельности таблицы разделов.
Вот тут было найдено неимоверное количество информации, относящейся конкретно к обновлению флеш памяти устройств на RK2918. Все описанные устройства это таблетки, и подключать их к компьютеру для обновления несколько проще (учитывая встроенный порт microUSB, он же USB OTG).

Вот так выглядит файл parameter:
FIRMWARE_VER:1.2.3
MACHINE_MODEL:SUNVEK
MACHINE_ID:007
MANUFACTURER:rock-chips
MAGIC: 0x5041524B
ATAG: 0x60000800
MACHINE: 2929
CHECK_MASK: 0x80
KERNEL_IMG: 0x60408000
CMDLINE: console=ttyS1,115200n8n androidboot.console=ttyS1 init=/init initrd=0x62000000,0x300000 mtdparts=rk29xxnand:0x00002000@0x00002000(misc),0x00004000@0x00004000(kernel),0x00002000@0x00008000(boot),0x00004000@0x0000A000(recovery),0x00080000@0x0000E000(system),0x00082000@0x0008E000(backup),0x0003a000@0x00110000(cache),0x00100000@0x0014a000(userdata),0x00002000@0x0024a000(kpanic),-@0x0024c000(user)

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

Размер считанного блока parameter — 0x200 (из исходных файлов RK29kitchen), это 512, а размер файла 262144 байт. Получается что размер условного блока это 262144/512, то есть 512 байт, что подтверждает и документация к rkflashtool.
Что занимает память между 0x200 и 0x2000, а это целых 3.75МБ — загадка.

parameter (таблица разделов) 256КБ
misc 4МБ
kernel 8МБ
boot 4МБ
recovery 8МБ
system 256МБ
backup 260МБ
cache 116МБ
userdata 512МБ
kpanic 4МБ
user всё оставшееся место

Препарация


Теперь у меня в руках набор img файлов, образов диска, которые я скачал. Интересно, что внутри. Из ранее полученных знаний мне известно, что для записи файлов, не предназначающихся для изменения (как то ядро ОС) на флеш память делают в формате cramfs, но некоторые особо хитрые китайцы умудряются то добавлять к этим образам ещё заголовки и подвалы, то использовать gzip, видимо, пытаясь затруднить чтение своих и создание собственных образов.

Именно это чудо, прозванное в народе crapfs, я и увидел:
$ sudo mount -t cramfs Image/boot.img /media/cramfs
mount: wrong fs type, bad option, bad superblock on /dev/loop0

$ dmesg |tail
[41549.071136] cramfs: wrong magic

При попытке подключения тем же RK29kitchen'ом результат примерно тот же:
/sbin/e2fsck: Bad magic number in super-block while trying to open system.img

Нужно обрезать первые 8 байт из img файла:
$ dd if=boot.img of=bootimg.gz skip=8 bs=8 count=20000000
524280+0 records in
524280+0 records out
4194296 bytes (4.2 MB) copied, 4.41275 s, 950 kB/s

Отлично. Мне попался тот самый случай, когда файлы пакуются gzip'ом, а потом к ним добавляется нелепый заголовок и подвал, в которых находится CRC и, наверное, ещё что-то.

Дальше — интереснее:
$ mkdir myboot
$ cd myboot
$ gunzip < ../bootimg.gz | sudo cpio -i --make-directories
$ ls
data          dev   init_battery.sh   init.rc            proc              sbin  system               ueventd.rc
default.prop  init  init.goldfish.rc  init.rk29board.rc  rk29xxnand_ko.ko  sys   ueventd.goldfish.rc  ueventd.rk29board.rc

Там внутри куча файлов, не слишком понятно, нужных или нет. Собирать это дело в обратном порядке нужно ещё аккуратнее, нужно сбросить даты на файлах:
$ find . -exec touch -d "1970-01-01 01:00" {} \;
$ find . ! -name "." | sort | cpio -oa -H newc | gzip -n >../customboot.gz
$ cd ..
$ rkcrc -k customboot.gz customboot.img


Для сборки образов традиционно использовуется cpio. По сравнению с более ходовым tar, cpio имеет ряд преимуществ, углубляться в которые я в этом топике не хочу.

И вот, у меня на руках собраный своими руками customboot.img, который можно залить обратно в устройство.
С kernel.img такая препарация не проходит.

А вот что вышло с system.img:
$ sudo mount -t cramfs system.img /media/cramfs
$ ls /media/cramfs/
app  bin  build.prop  etc  fonts  framework  lib  media  tts  usr  xbin

В папке app нашлись Android'овские APK файлы (архив исполняемого файла). То есть можно туда добавить какие-нибудь новые программы или удалить те, которые есть, включая какой-нибудь назойливый и надоевший. В bin можно добавить su и busybox, что как я понимаю, достаточно для рутирования устройства. В etc поменять конфигурацию. И так далее. В теории. На практике придётся несколько повозиться с тем, что в примонтированный образ cramfs просто так записать ничего не получится.

Ну, кое-что препарировать удалось.

Новый образ


Было бы, конечно, здорово попробовать загрузиться с SD карты, загрузив туда заботливо приготовленный кем-нибудь образ, но такой возможности у RK29 нет, поэтому придётся создавать образ, и прошивать его прямо во флеш память устройства. Уповаю на то, что есть резервная копия.

Образы, препарированные в предыдущем параграфе, все были в разных форматах, а именно:
boot.img был в формате crapfs, а остальные, которые уже загружаются после него — в более удобоваримых. Отсюда предположу, что танцы с бубном предстоят только с этим boot.img, а с остальными образами всё будет более-менее обыденно.

Освежу память, напишу какие разделы нужны для установки Linux.
/ Корневой раздел. Содержит важную папку /boot, содержащую в себе образ ядра. /boot можно сделать и отдельным разделом, с другой, не журналируемой, файловой системой (так как используется оно только при загрузке и обновлении ядра). Но для простоты можно держать её и в корневом разделе. Другая важная папка, /home, содержит пользовательские данные, и неплохо выделить для неё отдельный раздел. Swap, нужен для виртуальной памяти для устройств с менее, чем 1ГБ памяти, однако использовать под это дело встроенную флеш-память с ограниченным циклом чтения-записи как минимум неразумно, лучше потом подцепить для этих целей внешнюю SD карту. /usr хранит общие для всех пользователей файлы. /var, хранит логи, и тоже логичнее бы было хранить их на внешней SD карте.

Итак, чтобы меньше работать, сделаю-ка я образ, состоящий из трёх разделов:
/boot, 16МБ с файловой системой crapfs
/, ~4ГБ оставшееся место под корневую файловую систему
/home создавать не будем, поживём пока под root'ом, а как получится подмонтировать внешнюю SD карту, так её и подмонтируем
/swap тоже смонтирую на внешней флеш-карте

Скачал и распаковал последнее ядро с открытым кодом, которое заточено под Rockchip 2918, от odys.de. Версия ядра 2.6 опечалила. Инструкции по кросс-компиляции ядра от Archlinux ARM заставили почуствовать себя тупицей, а список поддерживаемых устройств расстроил. Yoctoproject слегка запутал. Обилие сборок Linaro и, опять же, ограниченный список поддерживаемых устройств, а также немалое количество багов даже на поддерживаемых устройствах, ввело в замешательство. Уже начал поглядывать в сторону LFS. Неужели нету чего-то универсального, что с полтычка бы завелось на более-менее стандартном оборудовании на базе Cortex A8/A9? Уфффф.

Мне не оставили выбора, придётся кросс-компилировать ядро из исходников и собирать образы самостоятельно. Скачал исходные коды ядра linux-linaro-3.5-rc3-2012.06.tar.bz2 и набор инструментов для кросс-компиляции gcc-linaro-arm-linux-gnueabihf-2012.06-20120625_linux.tar.bz2. Досадно только то, что для компиляции требуется специфичный для устройства .config файл, которого для RK2918 у Linaro нет. К счастью, в упоминавшемся чуть ранее ядре от odys есть специфичные для Rockchip файлы, и также они нашлись в исходниках поновее от easypix.eu. Их-то я и скопировал в исходники от Linaro, а именно:
— папку arch/arm/mach-rk29
— 50-килобайтный arch/arm/configs/rk29_ddr3sdk_defconfig с огромным количеством специфичных для устройства опций
— последнуюю строку из arch/arm/tools/mach-types
— раздел ARCH_RK29 из arch/arm/Kconfig
— mkkrnlimg из корня исходников

Кросс-компиляция ядра



3.5.0-rc3 от Linaro

$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- rk29_ddr3sdk_defconfig
$ PATH=$PATH:~/linaro/gcc-linaro-arm-linux-gnueabihf-2012.06-20120625_linux/bin
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- uImage
...
kernel/cgroup.c:470:2: error: 'saved_link' undeclared (first use in this function)
...
make: *** [kernel] Error 2

Довольно мило, но поправимо. Оказывается, кто-то заботливо стёр две строчки и комментарий. Я помню, это называется оптимизация использования памяти и рефакторинг, но мне это в этот раз не подходит, и придётся вернуть на место:
static void __put_css_set(struct css_set *cg, int taskexit)
{
  struct cg_cgroup_link *link;
  struct cg_cgroup_link *saved_link;

Сработало. Интересно, стабильные сборки от Linaro вообще пробуют собирать, как туда пробираются ошибки компиляции?

Ещё одна ошибка:
fs/yaffs2/yaffs_vfs.c:46:28: fatal error: linux/smp_lock.h: No such file or directory

Файл нашёлся в исходниках от odys, но возникла и другая ошибка, и ещё с десяток других:
fs/yaffs2/yaffs_vfs.c:317:3: error: assignment of read-only member ‘i_nlink’
...
fs/yaffs2/yaffs_vfs.c:1995:9: error: ?struct mtd_info? has no member named ?sync?
fs/yaffs2/yaffs_vfs.c:1996:6: error: ?struct mtd_info? has no member named ?sync?
fs/yaffs2/yaffs_vfs.c:2097:2: error: ?struct mtd_info? has no member named ?erase
...

Исключать yaffs2 из сборки? Править код на C, в котором я ничего не понимаю? С первой ошибкой я справился, потом нашёлся патч, который ни капли не помог, и пришлось исправлять наобум, ориентируясь на inode.c. Остались ошибки со struct mtd, и надо сказать, что в версии ядра от Android 3.4, всё то же самое, и пришло чуство, что надежды ждать неоткуда. Пришло чуство, что день раннего утра мудренее. Но желание убрать все строки, связанные с YAFFS из .config и продолжить оказалось сильнее. Потом можно использовать UBIFS, или на крайний случай даже ext3, не предназначенную для флеш носителей.

Награда была скорой:
Image Name:   Linux-3.5.0-rc3
Created:      Tue Jul  3 05:35:58 2012
Image Type:   ARM Linux Kernel Image (uncompressed)
Data Size:    2258064 Bytes = 2205.14 kB = 2.15 MB
Load Address: fffffff2
Entry Point:  fffffff2
echo '  Image arch/arm/boot/uImage is ready'
  Image arch/arm/boot/uImage is ready

Идём дальше:
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules
...
  CC      drivers/media/video/gspca/gspca_main.mod.o
  LD [M]  drivers/media/video/gspca/gspca_main.ko
  CC      drivers/scsi/scsi_wait_scan.mod.o
  LD [M]  drivers/scsi/scsi_wait_scan.ko

Всё прошло успешно, и только насторожило то, что ничего специфичного RK29 скомпилировано не было, и это очень подозрительно. uImage получен.

3.0.8+ от easypix.eu

На всякий запасной случай решил попробовать собрать исходники от easypix.eu. Тут отчётливо видно, что исходники RK29 компилируются. В .config'е YAFFS'а нет, равно как и UBIFS. Есть только предназначенный исключительно для чтения cramfs, который подойдёт для /boot, но совсем не подойдёт для корневого раздела. Сборка падает на:
  CC      drivers/net/wireless/bcm4329/wl_iw.o
drivers/net/wireless/bcm4329/wl_iw.c: In function ‘wl_iw_set_pmksa’:
drivers/net/wireless/bcm4329/wl_iw.c:5069:5: error: array subscript is above array bounds [-Werror=array-bounds]

Исправил .config, удалил оттуда WiFi модуль BCM4329 и добавил все возможные файловые системы для флеш памяти. Не понял, будет ли компилироваться драйвер RTL8192, ну и ладно. Продолжаю и прихожу к успеху:
  OBJCOPY arch/arm/boot/Image
  Kernel: arch/arm/boot/Image is ready
  UIMAGE  arch/arm/boot/uImage
Image Name:   Linux-3.0.8+
Created:      Thu Jul  5 13:29:41 2012
Image Type:   ARM Linux Kernel Image (uncompressed)
Data Size:    7028772 Bytes = 6864.04 kB = 6.70 MB
Load Address: 60408000
Entry Point:  60408000
  Image:  arch/arm/boot/uImage is ready


Чудовище

Доктор Франкенштейн бросает природе вызов и будет скрещивать последнее ядро с теми останками, что подбросил нам easypix.

Очень подмывает создать HWpack для Linaro, но опыта в этом деле нет, желания поддерживать в одиночку — тоже. Так что берём последнее ядро из Linaro git и буду на него постепенно накатывать то, что нужно для нормальной работы RK29.

Итак, теперь .config и Kconfig у меня от easypix.eu. Понял, что в прошлый раз забыл добавить в arch/arm/Kconfig строчку:
source "arch/arm/mach-rk29/Kconfig"


и в Makefile:
machine-$(CONFIG_ARCH_RK29)       := rk29
<source>

После запуска:
<source>
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- rk29_ddr3sdk_defconfig


добавил в .config следующее:
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
CONFIG_UBIFS_FS=y
CONFIG_UBIFS_FS_ADVANCED_COMPR=y

Но это ещё далеко не всё. Поиск 'rk29' по исходникам дал 10707 совпадений в 358 файлах, которые предстоит смерджить, среди них драйвера аудио, кодеки, Makefile'ы, Kconfig'и, разбросанные ровным слоем по всему проекту.

Оставлю это за кадром этого топика. Как только получится, обязательно обновлю топик и выложу исходники и результаты. Если есть желающие присоединиться к моему порыву — пишите.

Дистрибутив


Как известно, ядром единым сыт не будешь, и к нему полагается подавать GNU. Тут описано что и зачем нужно, чтобы превратить ядро в полноценную операционную систему.

В идеале хочется Arch Linux, и как написано на их сайте, можно взять дистрибутив под любое другое устройство и просто добавить своё ядро. Ядро у меня уже есть, так что осталось распаковать скачанный ArchLinuxARM-am33x-latest.tar.gz, удалить из него /boot, подивившись насколько же велико полученное самостоятельно ядро (почти 7МБ) в сравнении с ядром для BeagleBone (2.7МБ). Папка root, из которой я собираюсь сделать образ корневого раздела, занимает около 421МБ, 10% из которых занимают совершенно лишние в моей ситуации исходники ядра (linux-3.2.18-1).

Сборка и заливка



Подготовка


Итак, у меня есть две папки, boot и root, из которых нужно сделать два образа, причём первый в crapfs, а второй в какой-то файловой системе знакомой ядру и, желательно, предназначенной для флеш памяти. Выбор файловой системы для корневого раздела у меня обширен, так как ядро от easypix.eu собралось с поддержкой и JFFS2, и UBIFS, и EXT[2|3|4], и VFAT и MSDOS. В сети хвалят YAFFS2, он немного быстрее UBIFS и использует чуть меньше оперативной памяти, но сборка опять выдавала ошибки при попытке его подключения в .config, так что пускай будет UBIFS.

Помимо сбора образов нужно составить новую таблицу разделов и точку входа в ядро, а именно файл parameter, который занимает 256КБ памяти в начале флеш памяти, который я привёл в начале топика.

KERNEL_IMG, совпадает с тем, что выдало ядро по окончании сборки, так что менять не нужно. CHECK_MASK одинаков для всех виденных мной образов, тоже не трогаю. Остальные строки тоже, кроме CMDLINE, содержащей таблицы MTD разделов и аргументы загрузки.
На сайте U-Boot сказано о том, что таблицу разделов MTD можно задать и в упрощённом виде, но я рисковать не стану, и буду близок к оригиналу насколько это возможно.

Итак, память в устройсте распределяется следующим образом:
256КБ на файл parameters
16МБ на /boot (на случай, если вдруг захочется перезалить исключительно ядро, а оно перерастёт 8МБ)
остаток на /

Выглядит это так:
mtdparts=rk29xxnand:0x00008000@0x00002000(kernel),-@0x0000a000(system)

До:
CMDLINE: console=ttyS1,115200n8n androidboot.console=ttyS1 init=/init initrd=0x62000000,0x300000 mtdparts=...

Вроде бы в ядре Linux, начиная с 3.0, консоли стали именоваться по-другому, tty01 и т.д., но оставлю как есть.
androidboot.console и init нам не понадобятся. Initrd (диск в памяти, который используется для сборки и динамической подгрузки модулей) я решил не делать, возможно, зря. Нужно установить нахождение root раздела, ткнув ему в нужный mtd раздел (нумерующихся начиная с 0). Ещё нужно указать тип файловой системы для корневого раздела.

Итого получается:
CMDLINE: console=ttyS1,115200n8n root=/dev/mtdblock1 rootfstype=ubifs noinitrd mtdparts=rk29xxnand:0x00008000@0x00002000(kernel),-@0x0000a000(root)


Сборка



Таблица MTD разделов и параметры запуска ядра

Запускаю mkkrnlimg из RK29kitchen:
$ mkkrnlimg -a parameter parameter.img
F535BA01

$ ls -l
 316 Jul  5 22:56 parameter
 328 Jul 10 20:27 parameter.img

Смущает то, что исходный parm.img, извлечённый с устройства, имеет размер 256КБ, и содержимое там находится аж в пяти разных местах. А тут только в начале файла. Скорее всего, китайцы подстраховались на случай, если U-Boot будет пытаться грузить эти данные по другому смещению в памяти, и залили его дополнительно со смещением +16КБ, +32КБ, +48КБ и +64КБ. Не исключено, что оставшиеся 3.75МБ, которые, судя по таблице разделов, ничем не заняты, тоже содержат тот же самый кусок.
Различаются всего на 12 байт, 8 из которых добавлено в начало. Увы, сравнение с оригинальным parm.img показало, что mkkrnlimg добавляет
KRNL<
и 0x01, а в parm.img было
PARMG
и 0x02.
Шестнадцатиричный редактор из mc помогает, и я подправляю заголовок, чтобы был как в оригинале.

Ядро


$ mkkrnlimg -a uImage kernel.img
7DDF79C6

$ ls -l
   7139328 Jul  5 22:49 uImage
   7139340 Jul 10 20:42 kernel.img
<source>

Различаются всего на 12 байт, 8 добавлено в начало, и подозреваю, что 4 в конец. Такого, как было с boot.img (заголовок на 8КБ, запаковка gzip'ом и cpio) нет в помине.

<h5>Корневой в UBIFS</h5>
Немного теории специально для тех, кто не понял <a href="http://www.linux-mtd.infradead.org/faq/ubifs.html#L_mkfubifs">ЧаВо</a> (включая меня), <a href="http://lists.infradead.org/pipermail/linux-mtd/2008-April/021189.html">тут</a>.
Выясняется, что неплохо бы знать размер erase блока и размер страницы для используемой NAND флеш памяти. На плате устройства обнаружен чип с маркировкой Samsung 201 K9GBG08U0A SCB0, по <a href="http://gxwy.en.alibaba.com/product/530746803-213362683/IC_Samsung_Nand_Flash_Flash_Memory_K9GBG08U0A_SCBO.html">найденной</a> спецификации 4ГБ, размер erase блока значится 128КБ+4КБ, а размер страницы 2КБ.
Из полученного выбираю параметры для создания образа UBIFS и из него образа UBI и состав ubinize.cfg:
<source>
[ubifs]
mode=ubi
image=ubifs.img
vol_id=0
vol_size=4000MiB
vol_type=dynamic
vol_name=rootfs
vol_flags=autoresize


$ mkfs.ubifs -q -r ~/gv2b/root -m 2048 -e 131072 -c 32767 -o ubifs.img
$ ubinize -o ubi.img -m 2048 -p 128KiB ubinize.cfg
$ ls -l
221904896 Jul 10 01:14 ubifs.img
229376000 Jul 10 01:17 ubi.img

UBIFS поддерживает сжатие данных, а я ограничил размер тома 4ГБ при аналогичном размере физического носителя, не уверен, что это верное решение.

Прошивка


Немного смущает то, что для записи образов UBI желательно использовать специальный алгоритм.

Параметры начальной позиции и размера к rkflashtool задаются в блоках размером 512 байт.
Образ таблицы разделов parameter.img пишу по пяти разным смещениям, как у китайцев. Остальное согласно таблице разделов.
$ rkflashtool29 w 0 1 < parameter.img
$ rkflashtool29 w 0x00000020 1 < parameter.img
$ rkflashtool29 w 0x00000040 1 < parameter.img
$ rkflashtool29 w 0x00000060 1 < parameter.img
$ rkflashtool29 w 0x00000080 1 < parameter.img

$ rkflashtool29 w 0x00002000 0x00008000 < kernel.img
$ rkflashtool29 w 0x0000a000 0x0006d600 < ubi.img
<source>
В принципе пишется быстро, судя по последнему куску размером почти 4ГБ у меня получилось меньше минуты, но вот при запуске каждый раз происходит инициацилизация, занимающая 50 секунд. В любом случае процедура не заняла и десяти минут.
На всякий случай штатным образом перегружу устройство:
<source>
$ rkflashtool29 b


Метод проб и ошибок



Первый запуск


Первый запуск прошёл не то, чтобы не успешно, а прямо таки скажу, провально. Устройство не включило диод, не реагировало на нажатие кнопок, и ничего не выдало по HDMI. Очень удачно, что всё-таки сделал резервную копию. Очень удачно, что устройство всё ещё в состоянии принимать данные. Восстанавливаю в исходное состояние:
rkflashtool29 w 0 0x00082000 < backup.img

Устройство продолжает не работать.

Запускаю ./menu.sh из RK29kitchen, меняю размер раздела /system в резервной копии и прошиваю. Устройство включается, и показывает строку «Loading...», но дальше не идёт. Уже неплохо. Восстанвливаю оригинальную резервную копию, после второй перезагрузки загружается таки Android в первозданном виде.

Что я делал так и что не так


После копания в исходниках RK29kitchen и на форуме, на котором аннонсировался rkflashtool, выяснилось, что я не зря приписывал этот образ по пяти разным смещениям, и что так и нужно (90.flash.sh).

Файл parameter.img содержит «PARM» в первых четырёх байтах, а следующие два, которые я ошибочно скопировал из оригинального parm.img — это длина файла parameter, 583 байта. Это объясняет, почему ничего не грузилось (не определялась таблица MTD разделов и U-Boot не мог загрузить ядро), но не объясняет почему не горела лампочка. Вместо припрялсываний с шестнадцатеричным редактором обнаружилась утилита rkcrc, которая делает из файла parameter образ с правильным заголовками и общим размером 16КБ, будучи запущена с опцией "-p". Опция "-k" предназначена для создания образов с меткой «KRNL».

Покопался в оригинальном backup.img. Не ясно, стоило ли так радикально менять таблицу разделов, в файле отчётливо читается, что размеры, смещения и порядок (разделы должны идти в порядке смещения) разделов менять можно, а также можно создавать новые разделы, а вот названия разделов менять нельзя. Кто именно задаёт такое ограничение — не ясно, но скорее всего загрузчик (U-Boot?).
Там же обнаружилось, что используется RK29xxLoader(L)_V2.08.bin (чуть далее явно идёт бинарник версии 2.04), в то время как в списке загрузчиков RK29kitchen обнаружились также версии 2.12, 2.14 и 2.18, а в Nextbook'е так и вообще используется 2.20. Как обновить загрузчик, находящийся на NOR флеш памяти (которой всего 1МБ или около того), и стоит ли это делать — не ясно. Помимо загрузчика, там ещё находится файл package-file, содержащий немало интересной информации.

Попытка номер два, паника и уныние


Повторяю всю процедуру прошивки, но теперь с правильным parameter.img. Не получается. Восстанавливаю обратно.
В какой-то момент сдуру вместо того, чтобы воспользоваться RK29kitchen, записал backup.img прямо по смещению 0. Потом резервную копию восстановил, ещё раз снял дамп и лишние резервные копии затёр. Обновление прошивки из резервной копии в какой-то момент не сработало. Наступила паника от того, что мне показалось, что я затёр ту самую изначальную резервную копию, с правильным backup.img. Написал скрипт, чтобы восстанавливать из отдельных образов, но и он не помог. Хотя бы лампочка при включении устройства загорается. Но по HDMI никакого сигнала нет.
Задумался об extundelete, но поняв, что потребуется chroot и umount, отказался от этой мысли в страхе запороть систему не только на недорогом китайском устройстве.
Прошивал все возможные прошивки, от gbox (немного другого устройства всего с тремя портами USB), от автора метода прошивки, найденные вот здесь. Ничего не помогало. Всё равно кирпич, иногда со светодиодом при включении, а иногда и совсем без. Наступило раннее утро, и я в очередной раз решил, что вечер раннего утра мудренее.

И как я оказался прав. Подключив устройство к монитору, оказалось, что всё работает.

Выводы и изыскания

Подобный опыт, хоть и не слишком приятен, но привёл меня к следующим заключениям и находкам в сети:
— устройству нужно время, чтобы после прошивки переформатировать разделы
— в некоторых прошивках есть загрузчик, иногда 2.08, иногда 2.14. Куда его прошивать — не ясно. Автор RK29kitchen ответа на этот вопрос не смог получить
— таинственный package-file возможно как раз находится в загадочном пространстве между parameters и ядром, и также не исключено, что там же находятся загрузчик и не менее загадочный HWDEF, описывающий парметры устройства

Из одной из прошивок:
HWDEF 0x00000800  0x0000031B
package-file  0x00001000  0x00000216
RK29xxLoader(L)_V2.08.bin 0x00001800  0x000225BE
parameter 0x00024000  0x00000251


Попытка номер три


Первым делом сделал полный дамп всех 4ГБ флеш-памяти.

Пробую залить ядро из резервной копии, распаковав его и запаковав заново. Если не будет работать — значит, что-то не так пакую.

Распаковываю, запаковываю и прошиваю:
mkkrnlimg -r kernel.img kernelimg
mkkrnlimg -a kernelimg kernel2.img
rkflashtool29 w 0x00004000 0x00004000 < kernel2.img

Перегружаю — работает. Тот же самый трюк с самостоятельно полученным uImage не проходит.

Ещё при распаковке c помощью RK29kitchen оригинального kernel.img обнаружилось, что внутри у образа сигнатура отличается от стандартной по версии U-Boot 27 05 19 56. Все разнообразные образы ядра из разных прошивок имеют одинаковый заголовок:
D3 F0 21 E3   10 9F 10 EE   xx xx 00 EB   05 A0 B0 E1   xx xx 00 0A

Первая мысль — по образу прошлись XOR'ом. Проверяю, но, к сожалению, 8 и 16 битные не подходят, а 32 битный по четвёртому квартету выдаёт слишком большое число, чтобы оно могло быть размером образа, да и то, что в третьем квартете, в котором должно быть время, слишком уж много совпадений между разными образами.

Поисковый запрос по «D3 F0 21 E3» показывает крайне мало результатов, а среди них ещё меньше интересных. Вот в этой ветке итальянского форума заявлено, что исходники от Odys не создают корректного образа, в отличии от вот этих исходников ядра от Anypad.
А возможно, что проблема в использовании мной mkkrnlimg из RK29kitchen, ведь к исходникам от Odys и easypix прилагается (кстати, одинаковый) mrkrnlimg, который сильно отличается размером и умеет конвертировать только в одну сторону. Нет, созданные всеми тремя утилитами образы ничем не отличаются.

Собираю ядро от Anypad. Оно 2.6, но интересно посмотреть, какой заголовок будет у uImage. Избавился от той же ошибки с модулем bcm4329.

Случайно заметил, что в моём .config файле включён выход на накую-то LCD панель, а опция DEFAULT_OUT_HDMI выключена. Это огромный прокол. Не удивился бы, если бы Linux загрузился, но ничего не показывал по HDMI, и я так бы и не узнал, что он загрузился. Обнаружилась связанная с этим DEFAULT_OUT_HDMI проблема в rk29_fb.c, не нашлось функции hdmi_get_default_resolution, причём в исходниках от easypix её тоже нет. Пришлось писать её наощупь, проставляя более десятка параметров. В структуре, которую эта функция заполняет, есть забавный параметр перемены местами цветовых каналов RGB.

Собрался образ, но в нём те же злосчастные стандартные «27 05». И тут я осмотрелся, и в том же каталоге заметил образ Image, и в нём лежит долгожданный заголовок «D3 F0». Посмотрел в результаты сборки ядра easypix — и там тоже такой есть. Приятная неожиданность.

Нельзя обойти вниманием такую интересная вещь, как zImage, самораспаковывающийся архив с образом ядра. Ради интереса собрал zImage и, разница в размере впечатляет. Для раздела с ядром явно хватило бы и 8МБ, с большим запасом. Кстати, почти вдвое отличается и от так называемого «zImage» (который на самом деле просто Image), извлечённого из образа ядра устройства (5.8МБ).
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage
$ ls -l arch/arm/boot
 7135268 Jul 13 03:37 Image
 7139328 Jul  5 21:41 uImage
 3408472 Jul 12 00:20 zImage

Ну, теперь в получившийся образ остаётся только добавить заголовки и прошить. Хочу заметить, что rkcrc -k и mkkrnlimg -a дают один и тот же результат.
Прошил, включил — не горит диод. Что-то не выходит с ядром. Подправил расходящиеся с оригиналом байты заголовка (который ещё до CRC, конечно), добавил заголовки, прошил — не работает. Вернул старое ядро на место.

Закралась мысль посмотреть в раздел /kpanic, не зря же его выделили. Скачал, но увы, там только что-то относящееся к панике штатного ядра 2.6.32.27.

Отчаялся прошивать своё ядро.

Попытка номер 4


Ну, раз ядро прошить не удалось, может быть получится прошить всё остальное, оставив только ядро. Посколько с набега взять не получилось, буду делать маленькие шажки.

Небольшой экскурс в теорию. Как вообще загружается Android на устройстве?
1. При включении из NOR памяти (напрямую, так как она поддерживает execute-in-place) запускается загрузчик, U-Boot.
2. U-Boot загружает таблицу MTD разделов и загружает ядро Linux из образа в память.
3. Linux инициализирует драйвера устройств, монтирует разделы и т.п., а потом запускает init из /.
4. init…
дальше не интересно, потому что это уже Android'овый init, и как раз вместо него хочется записать свой, от Arch Linux.

init находится в корне, а в дистрибутиве Arch Linux он находится в /sbin. Ничего другого не остаётся, как скопировать его в корень.

В оригинальном Android'е файл init находится не в разделе system, а в boot. То есть именно этот boot раздел монтируется в корень, а system монтируется в /system. Так и оставлю.

В оригинальном boot разделе лежит rk29xxnand_ko.ko, модуль, очевидно, предназначенный для работы с NAND флеш памятью. Остальные модули лежат в /lib/modules/3.2.18-1/kernel, а ссылки на них прописаны в /lib/modules/3.2.18-1/modules.order. Пакую gzip'ом прилагающийся ko, кладу к остальным модулям, относящимся к nand, в kernel/drivers/mtd/nand, ставлю на него права root.root, и прописываю его в modules.order и modules.dep. Вряд ли это поможет ядру найти нужный модуль, но заставить depmod копаться в ELF'ах другой архитектуры и находить зависмости у меня не вышло.

Оригинальное ядро ничего не знает о UBIFS, поэтому созданный ранее образ придётся оставить в сторонке, а собирать буду с помощью cpio, gzip и mkkrnlimg:
$ find . -exec touch -d "1970-01-01 01:00" {} \;
$ find . ! -name "." | sort | sudo cpio -oa -H newc | gzip -n >../boot.gz
$ cd ..
$ mkkrnlimg -a boot.gz boot.img
$ ls -l boot.img
 155166888 Jul 13 20:55 boot.img

Увы, раздел boot слегка маловат, и придётся слегка подправить parameters, расширив его и подвинув остальные разделы, для простоты редактирования расширю его на 512МБ (0x00100000):
CMDLINE: console=ttyS1,115200n8n androidboot.console=ttyS1 init=/sbin/init initrd=0x62000000,0x300000 mtdparts=rk29xxnand:0x00002000@0x00002000(misc),0x00004000@0x00004000(kernel),0x00082000@0x00008000(boot),0x00004000@0x0008A000(recovery),0x00080000@0x0008E000(system),0x00082000@0x0010E000(backup),0x0003a000@0x00190000(cache),0x00100000@0x001ca000(userdata),0x00002000@0x002ca000(kpanic),-@0x002cc000(user)

Заодно нашёлся и путь до init файла, поправил его тоже на /sbin/init. Пакую:
$ rkcrc -p parameter parmnew.img
$ ls -l
 16384 Jul 13 21:13 parmnew.img

Кстати сказать, у разделов cache, kpanic и userdata принято стирать первые 256КБ, а раздел user вообще не трогать, как я почерпнул из исходников RK29kitchen, но меня разделы идущие после system волнуют мало. Разделы misc и kernel не меняю. В boot заливаю Arch Linux, остальное перетираю целиком.
$ rkflashtool29 w 0 1 < parmnew.img
$ rkflashtool29 w 0x00000020 1 < parmnew.img
$ rkflashtool29 w 0x00000040 1 < parmnew.img
$ rkflashtool29 w 0x00000060 1 < parmnew.img
$ rkflashtool29 w 0x00000080 1 < parmnew.img
$ rkflashtool29 w 0x00008000 0x00082000 < boot.img
$ rkflashtool29 e 0x0008a000 0x006f6000
$ rkflashtool29 b

Чуть досадно не ошибся в размере boot.img и дальнейшем смещении для стирания. Интересно, сколько подобных ошибок я уже допустил? Может, и не родное ядро бы нормально запустилось?

После перезагрузки проходит секунд 10, потом загорается светодиод. И, о чудо! Появился пингвин в левом верхнем углу экрана, минут десять повисел, а потом остался тёмно-синий фон, и больше ничего не происходило. При последующих загрузках пингвин появляется почти мнгновенно. Подключенная клавиатура не оказывает никакого эффекта. В kpanic чисто (ничего, кроме 00 и FF).


Заключение


Нужно быть неплохого уровня специалистом, чтобы без документации и исходников справиться с таким устройством, и этот специалист — явно не я. Либо устройство совсем уж не то, что нужно.

Очень хотел выложить те образы, что у меня получились, загрузить скриншоты и краткое видео с какой-нибудь новой 3D игрой, но не судьба. Согласитесь, неудачный опыт — тоже опыт.

Ссылки


Представляю сокращённый список того интересного, что я прочёл, что по каким-либо причинам не попало в ссылки к самому топику.

Прошивка, образы, железо


androidforums.com/google-tv/505559-flashing-android-tv-box-one-four-usb.html
androidforums.com/google-tv/506298-rk2918-android-tv-box-4x-usb-rooted-firmware-manual.html
androidforums.com/google-tv/413090-r-box-rockchip-2918-google-tv-3.html

sites.google.com/site/rk2918tools

thomaspolasek.blogspot.com/2012/04/arch-linux-lxde-w-xorg-mouse-keyboard_16.html

cxem.net/comp/comp70.php
github.com/OlegKyiashko/RK29kitchen

4pda.ru/forum/lofiversion/index.php?t337784-50.html
4pda.ru/forum/index.php?showtopic=319345
4pda.ru/forum/index.php?showtopic=313261

forum.xda-developers.com/showthread.php?t=1286305

www.androidtablets.net/forum/rockchip-rk2818-tablets/21291-problems-getting-image-dumped-rkdump.html
www.androidtablets.net/forum/rockchip-based/439-how-unpack-repack-custom-firmwares-rockchip-rk28xx.html

www.freaktab.com/showthread.php?287-RockChip-ROM-Building-Tips-and-Tricks-by-Finless
www.freaktab.com/showthread.php?401-Dumping-ROM-using-ADB-guide

www.arctablet.com/wiki/index.php/Rockchip_2918_devices_MTD_partitions_mapping

yanzicjustnubie.wordpress.com/2011/09/10/linux-installer-easy-way-to-install-debianubuntu-on-android chroot linux on android
wiki.debian.org/DebianInstaller/Arm/OtherPlatforms
www.arm.com/community/software-enablement/linux.php
code.google.com/p/beagleboard/wiki/LinuxBootDiskFormat

www.yoctoproject.org — build custom linux distro
www.freaktab.com/showthread.php?1053-RK2918-set-top-box-linux-installation
github.com/wendal/teclast_tools
wiki.archlinux.org/index.php/Partitioning#Partitions_in_a_GNU.2FUnix_system
Замечательный поисковый запрос

Прочее



Особого внимания достоин www.cnx-software.com, интереснейший сайт обо всём, связанном с ARM.

Другое интересное железо



Подборка с ценами
olimex.com/dev/index.html
rhombus-tech.net/allwinner_a10
www.hardkernel.com/renewal_2011/products/prdt_info.php?g_code=G133999328931
www.technexion.com/index.php/products/development-kits/infernopack
www.advantech.com/products/ROM-1210/mod_D5882807-78CE-4A64-AADA-FAEAA099F2CB.aspx
www.sigmadesigns.com/products.php?id=38
www.renesas.com/press/news/2012/news20120110.jsp
И прообраз всех этих HDMI stick'ов на процессоре строчкой выше.
www.cnx-software.com/2012/07/10/ippea-tv-android-4-0-3-hdmi-stick-based-on-ingenic-jz4770-mips-sells-for-50-usd

www.uplaytablet.com/compare-soc-cpus-used-in-ainol-elf-aurora-ii-amlogic-8726-mx-wopad-i7-i8-rock-chip-rk-2918-and-wopad-a10-allwinner-a10
rhombus-tech.net/evaluated_cpus — обзор различных процессоров для применения в компактных устройствах

en.qi-hardware.com/wiki/Main_Page

www.wits-tech.com/pages/board-en.jsp
www.pineriver.cn/eshowProDetail.asp?ProID=1527
www.calao-systems.com/articles.php?lng=en&pg=6186

www.st.com/internet/mcu/product/251211.jsp
www.st.com/internet/evalboard/product/253211.jsp

Установка GNU/Linux на железо



archlinuxarm.org/forum/viewtopic.php?f=27&t=2709 Mele A1000 Archlinux
rhombus-tech.net/allwinner_a10/hacking_the_mele_a1000
www.cnx-software.com/2012/06/13/hardware-packs-for-allwinner-a10-devices-and-easier-method-to-create-a-bootable-ubuntu-12-04-sd-card
gitorious.org/ac100/abootimg/blobs/master/README
Tags:
Hubs:
+27
Comments9

Articles

Change theme settings