Кросс-компиляция x86 -> arm. Установка Gentoo на RealView Emulation board.
Представляю отчет об установке Gentoo на отладочную плату RealView Emulation Board. Были получены следующие результаты: Gentoo собрана методом кросс-компиляции для архитектуры arm и загружена на плату RealView. Настроен загрузчик u-boot: ядро скачивается по tftp, корневая файловая система монтируется по NFS.
- Оборудование
- Плата RealView Emulation Board (arm, Gentoo)
- Сервер разработки, онже хост-машина (x86, Slackware, Gentoo из chroot)
- Установка Gentoo
Существует два основных способа установки Gentoo:
- Установить систему, используя stage3 архивы, после чего загрузиться с "настоящего" процессора. Поскольку у меня нет никакой готовой системы, пригодной для запуска arm-бинарников, то понадобилась бы виртуальная машина. Qemu вполне подойдет. Этот способ не должен вызвать затруднений, но я не буду искать легуих путей :) Ну да, кроме шуток, скорость компиляции будет довольно медленной, а кроме того, вместе с ситемой придется таскать компилятор.
- Скомпилировать систему кросс-компилятором. Если кто не знает - это когда компилятор выполняется на на одной платформе (x86), а код генерирует для другой (arm). Все необходимые средства для этого предусмотрены в portage.
Итак, идем вторым путем. Я выбрал для себя два основных ресурса, описывающих процесс. Это Gentoo Embedded Handbook (к сожалению, на момент написания этой статьи, книга была несколько устаревшей), и эта инструкция от разработчкиков проекта по портированию Gentoo на смартфон OpenMoko.
Рекомендую внимательно ознакомиться с Embedded hanbdook`ом, после чего смело следовать инструкциям от OpenMoko. Чтобы не повторяться, привожу только свои комментарии в форме "путевых записок":
- Выбор директории $SYSROOT целевой системы.
Решил следовать рекомендациям, и выбрал /usr/arm-module2-linux-gnueabi как корневое дерево для целевой системы. - Обертки над emerge.
В Handbook'е предлагается самостоятельно сделать обертку над emerge (и назвать её xmerge). В данный момент, эта работа уже проделана - в более свежей инструкции от OpenMoko советуют использоватьemerge crossdev-wrappers emerge-wrapper --init
В результате последней команды создадутся символические ссылки вида /usr/bin/emerge-* (например /usr/bin/emerge-arm-module2-linux-gnueabi), которые делают то же, что и обычный emerge, но только для целевых систем с корнем в /usr/* (в моем случе /usr/arm-module2-linux-gnueabi).
Кроме того, устанавливается скрипт /usr/arm-module2-linux-gnueabi/etc/portage/bashrc, затыкающий дырки в libtool при кросс-компиляции. Это довольно аккуратный хак, который позволит компилировать libtoolize`нутые программы, которых на самом деле, довольно много. Этот хак можно отключить (читать тут), но тогда проблем сильно прибавится. К сожалению, хак затруднит нативную сборку пакетов на целевой системе.
- Выбор профиля.
Тут возмрожны варианты, я взял профиль от OpenMoko. Также можно выбрать профиль embedded из стандартной поставки, но с содержимым репозитория OpenMoko ознакомиться все равно очень полезно. Например, из-за файлика portage-flags-host/arm-linux-gnueabi (см. дальше). - Отключение тестов configure, требующих выполнения кода на целевой платформе.
Многоие пакеты хотят выполнить тестовые программы на целевом процессоре на стадии configure. Поскольку в условиях кросс-комиляции это невозможно, тесты нужно пропускать. Для этого необходимо заранее спрогнозировать их результаты и определять специальные переменные окружения, которые имеют имена наподобие "ac_cv_func_malloc_0_nonnull".Думаю, что самым легким решением проблемы будет использовать файл portage-flags-host/arm-linux-gnueabi из репозитория оверлея OpenMoko.
Куда его девать? Либо определить все переменные из него перед запуском emerge-* как-нибудь так:`cat <путь_к_portage-flags-host/arm-linux-gnueabi> | grep -v '^#' | sed 's/\([a-zA-Z]\+\)/export \1/'`
Либо просто воспользоваться иструкциями OpenMoko, кинув ссылку на файл с переменными в волшебное место:
cd /usr/share/crossdev/include/site ln -s <путь_к_portage-flags-host/arm-linux-gnueabi> arm-linux-gnueabi
Теперь основные пакеты должны собраться без проблем. Но если при очередном emerge`е появилось сообщение об ошибке, говорящее что-то про недоступность тестов, значит пришла пора добавить определение новой перемнной. Алгоритм поиска её имени следующий: Окрываем подробный лог сборки (config.log) и нахдим в нем текст ошибки. В отличии от сокращенного варианта emerge, в этом сообщении будет указан номер строки ./configure. Чтож, открываем файл configure на этой строке и смотрим чуть выше. Обычно там бывает проверка некой переменной. Если её значение не пусто, то тест не выполняентся. Это как раз то, что нам надо, дальше дело техники: в гугле узнаем, за что отвечает переменная, выбираем ей занчение, затем пополняем файл-список и повторяем emerge.
- Проблема с запуском bash на целевой системе.
Забегая вперед, скажу, что при первом запуске системы, bash отказывался стартовать, поскольку не мог найти библиотеку, обычно идущую в составе gcc. В моем же случае, gcc был установлен только на хост машине, и потому оказывался недоступным при загрузке с платы. Я решил проблему ручным копированием /usr/lib/gcc* в /usr/arm-module2-linux-gnueabi/usr/lib/gcc и созданием нужных симлинков. Идея не очень хороша. Думаю, что обойти проблему можно было бы, отказавшись от bash в пользу busybox. Это одна из тех вещей, которые обычно определяют в профиле, а пройиль OpenMoko, который я выбрал, решил использовать классический набор утилит. - И, наконец, Проблема с libtool.
Проблема заключается в том, что при кросс-компиляции, некоторые пакеты пытаются линковаться с библиотеками, установленными в базовой системе (в /usr/lib), вместо того, чтобы слинковаться со "своими" библиотеками (в моем случае - из /usr/arm-module2-linux-gnueabi/usr/lib). Виноват libtool, разработчики которого забыли о том, что путь установки библиотеки не всегда совпадает с путем, по которому к ней будут обращаться. А теперь плохая новость - часто программы идут с _собственной_ версией libtool, и решить проблему "одним ударом" не получится. Вот пример сообщения об ошибке, которое появилось при попытке собрать gstreamer "по-честному":/usr/lib/libgobject-2.0.so: could not read symbols: File in wrong format
Авторы crossdev-wrappers предлагают следующий вариант решения проблемы: с помощью скрипта /usr/arm-module2-linux-gnueabi/etc/portage/bashrc, который подкладывается их wrappers`ами, они применяют патч к каждому пакету, который собирается для целевой системы (в данном случае - для всех пакетов с корнем в /usr/arm-module2-linux-gnueabi). Патч находит все *la файлы пакета - в них libtool ведет своеобразную базу данных о библиотеках - и прибавляет куда надо это самое /usr/arm-module2-linux-gnueabi. Достоинство решения - универсальность. Ведь база данных - единственное общее свойство всех libtool из разных пакетов. Недостаток - теперь воспользоваться libtoolом "изнутри" системы сложнее - ведь там все библиотеки будут располагаться в /usr/lib. Думаю, что это не очень фатально, поскольку в случае необходимости можно будет придумать обходной маневр с использованием симлинкa /usr/arm-module2-linux-gnueabi -> /.
Вобщем, я сделал для себя два вывода:
(1) libtool - зло, (2) нужно ждать ебилдовНапоследок, вот некторые ссылки по теме:
http://www.nabble.com/Cross-compile-and-libtool-td13912879.html
http://bugs.gentoo.org/show_bug.cgi?id=262298
http://bugs.gentoo.org/show_bug.cgi?id=272089
- Сборка ядра
Сборку ядра можно пропустить, взяв готовый бинарник с сайта поддержки RealView. Если без сборки ядра не обойтись, то тамже лежат типовые конфиги (которые /usr/src/linux/.config). Они послужат хорошей отправной точкой при разработке. В конце концов, отладочная плата представляет интерес в первую очередь для разработчиков новых устройств, а пересборка ядра - их любимое занятие:)
Стоит отметить, что для u-boot ядро должно быть преобразрвано в формат uImage. Для этого используется программа, скачиваемая все с тогоже сайта поддержки RealView.
- Настройка загрузчика отладочной платы
Плата RealView Emulation board грузится в три этапа. Вначале управление получает системный загрузчик "BootMonitor" (прошивается производителем, если слетит - то плате хана). Он, являясь маленькой однозадачной операционной системой, запускает u-boot (основной загрузчик) как внешнее приложение. Наконец, u-boot скачивает по tftp ядро линукса и передает управление ему.
u-boot может быть скомпилирован в различных конфигурациях, от которых зависит набор встроенных команд. Я воспользовался готовым u-boot, взятым с официального сайта Realview.- Настройка системного загрузчика "BootMonitor".
TODO - Прошивка загрузчика u-boot.
TODO - Настройка переменных окружения u-boot.
U-boot, также как и BootMonitor, является маленькой операционной системой, поскольку может запускать различные задачи по команде пользователя. Команды подаются с помощью командной строки, их описания есть документации u-boot. Вот самые полезные из них:- setenv <переменная> <значение> - Установить переменную окружения
- printenv - Распечатать все переменные окружения
- tftp - Загрузить ядро с сервера по протоколу tftp
- bootm - Передать управления загруженному ядру Linux
Команды tftp и bootm не имеют аргументов, но используют значения одних переменных окружения и присваивают значения другим. Словом, дело тонкое, нужно быть внимательным. Вот мой файл команд, настраивающий все u-boot для загрузки линукса:
setenv bootdelay 2 setenv loadaddr 0x200000 # Настройки сетевого интерфейса u-boot # Имена переменных должны быть именно такими (см. документацию # к команде tftf) setenv netmask 255.255.255.0 setenv gatewayip 192.168.0.1 setenv ipaddr 192.168.0.10 # Адрес tftp-сервера (хост-машины), с которого будет взято ядро setenv serverip 192.168.0.2 setenv ethaddr 00:02:F7:00:2F:DE # Путь к uImage-файлу ядра, на tftp сервере с адресом serverip setenv bootfile /home/smironov/filesystem_bin_armv6vfp_min/boot/uImage-2.6.28-arm1crypto_test # Переменные, формирующие командную строку ядра (для удобства) setenv rootpath /home/smironov/arm-module2-linux-gnueabi setenv ba_common mem=256M console=ttyAMA0 debug setenv ba_ip ip=$(ipaddr):$(serverip):$(gatewayip):$(netmask):armboard2::off setenv ba_nfs root=/dev/nfs nfsroot=$(serverip):$(rootpath) # Вся командная строка целиком setenv bootargs $(ba_common) $(ba_ip) $(ba_nfs)
Осталось взять этот файл, и выполнить его на u-boot, предварительно удалив комментарии, которых u-boot не умеет. Проблема в том, что дефолтный убут не умеет исполнять файлы, не имеет прямого доступа к файлам на хост-машине и вообще вещь довольно ограниченная. Можно, конечно, просто скопировать командный файл на консоль (методом Ctrl+C, Ctrl+V). Но это неудобно - хочется автоматизировать процесс. Первое, что приходит в голову - выводить файл на СОМ-порт (я использовал USB2COM переходник, поэтому мой порт называется /dev/ttyUSB0) как-нибудь так:
cat command-file | grep -v '^#' > /dev/ttyUSB0
Однако, мне не удалось добиться нормального вывода, вместо текста до платы доходил "мусор" (предполагаю, что проблема крылась в некорректно заданных режимах порта, но проверка скоростей и танцы с stty ни к чему не привели). В тоже время, minicom и его примитивный скриптовый движок runscript работали как часы. Поэтому, я сделал скрипт под названием miniboot для передачи текстового файла на удаленный терминал:
#!/bin/bash # Sends file via minicom function die() { echo "Error: $@" 2>&1 exit -1 } function usage() { echo 'Usage:' echo 'miniboot [script] BOARD' echo 'script : text files (e.g. with u-boot commands). ' \ 'Without this argument miniboot will use ~/.minibootrc file' echo 'BOARD : minicom session name ("blah" for /etc/minirc.blah)' exit -1 } script=$1 if [ -f "$script" ] ; then shift elif [ "$script" == "--help" ] ; then usage else script=~/.minibootrc fi test -f "$script" || die "Can't open file $script. Try $0 --help" args=$@ test -n "$args" || die "minicom arguments are empty. Try $0 --help" target=~/.miniscript echo -n > $target linesize=40 ((linesize2=linesize+1)) IFS=$'\n' echo "print Start loading..." >> $target # Domn runscript doesn't allow long command lines, so we'll slice them. for l in `cat $script` ; do if echo "$l" | grep '^#' >/dev/null ; then continue; fi while ((`echo $l | wc -c`>$linesize)) ; do echo $l | cut -b -$linesize | sed 's/\(.*\)/send \1\\c/ ; s/\$/\\\$/g' >> $target l=`echo $l | cut -b $linesize2-` done echo $l | sed 's/\(.*\)/send \1/ ; s/\$/\\\$/g' >> $target done echo "send " >> $target # Running minicom script engine exec minicom -S $target $args
Теперь, создав файл с командами u-boot можно "отправить его на выполнение". Достаточно включить плату, убедиться, что u-boot загружен и готов к приему команд, и можно выполнять скрипт. К примеру, для отправки файла loadgentoo.uboot на устройство, коннект к которому описан в профиле minicom с именем /etc/minirc.newboard, следует набрать:
miniboot loadgentoo.uboot newboard
В результате откроется minicom, который сначала выполнит скрипт, а потом перейдет в обычный режим работы. Теперь нужно убедиться, что все переменные корректно проинициаллизировались (набрав "printenv" после пригоашения ввода u-boot), и можно приступать к запуску ядра. Набираем tftp
(u-boot обращается к нашему tftp-серверу и берет ядро) и bootm (u-boot передает управление ядру, которое подхватывает командную строку и лезет на NFS за корневой файловой системой). все, на консоли загрузачный хаос, на мониторе (если он подключен к плате) - пингвин. - Настройка системного загрузчика "BootMonitor".
Плата подключается к серверу с помощью СОМ порта. Также обе машины подключены к сети по ethernet. Для доступа к COM могут быть использованы программы типа minicom или kermit. Я использровал minicom, потому что только её получилось приспособить для посылки данных на удаленный терминал.
Самый простой и удобный способ загрузить linux на плату - воспользоваться схемой "tftp+nfs". Это означает, что на сервере должны быть подняты демоны tftp (для загрузки ядра) и NFS (для экспорта корневой файловой системы). Об этом - см. man :) Ну все, теперь о главном:
Когда все настроено в соответствии с руководствами, можно запускать emerge-* system. В моем случае -
emerge-arm-module2-linux-gnueabi system
Процесс, как известно, не быстрый, поэтому можно попытаться расслабиться. Этому будут мешать разнообразные баги, которые обходятся отключением различных use-флагов. Например, у меня не собралась программа file с USE="python", а также ncurses с USE="unicode". Жаль, очень жаль. Меняем флаги и перезапускаем emerge.
- Блог пользователя - grok223
- Для комментирования войдите или зарегистрируйтесь
Скорость компиляции в qemu на
Скорость компиляции в qemu на athlon 64 3200+ сопоставима (может даже меньше), чем у xScale 400 Mhz. Вот только оперативки больше.
qemu
Qemu не подойдет :( Потому как xscale нефига не поддерживаться да и оперативки там можно задать максимум 128 МБ
Working on Gentoo Linux for Asus P535 and Qtopia :-)
материал хороший,
материал хороший, спасибо.
поправьте только ссылку на оверлей OpenMoko.
Если это тот же репозиторий что и подключается по layman -a openmoko, подскажите, где файл указанный в статье найти.