Практики проектирования файлов построения загрузочного образа
В этой статье:
В этой статье будут рассмотрены несколько типовых файлов построения загрузочного образа, которые можно использовать для создания образов целевых систем с помощью утилиты mkifs. Статья включает в себя две основных части:
В конце статьи находятся разделы, в которых указаны отличия каждой поддерживаемой платформы от x86 и аспекты, требующие особого внимания.
Мы рекомендуем изучать общий раздел этой статьи и раздел, посвященный конкретному процессору, поскольку в общем разделе рассматриваются компоненты, которые применяются почти в каждой системе (например, разделяемые объекты).
В этом разделе мы рассмотрим примеры файлов построения загрузочного образа, которые применимы к любой платформе (с незначительными изменениями, которые мы отметим). Сначала мы ознакомимся с фрагментами, которые иллюстрируют различные методы, а затем — с несколькими полными файлами построения загрузочного образа. В разделе "Примечания для конкретных процессоров" указаны изменения, которые необходимо вносить для поддержки различных семейств процессоров.
Сначала необходимо предоставить драйверам доступ к совместно используемым библиотекам. Всем драйверам требуется как минимум стандартная библиотека C (libc.so
или системная библиотека). Поскольку поиск совместно используемых библиотек осуществляется в каталоге /proc/boot
, достаточно включить их в образ. Для этого имя совместно используемой библиотеки указывается в отдельной строке файла построения загрузочного образа.
![]() | Компоновщик среды выполнения должен находиться в файле ldqnx.so.* , однако сейчас он находится в файле libc.so , поэтому мы создадим символьную ссылку на него в менеджере процессов. |
Для этого включим в файл построения загрузочного образа следующие строки:
# включение совместно используемой библиотеки Clibc.so# создание символьной ссылки на нее с именем ldqnx.so.2[type=link] /usr/lib/ldqnx.so.2=/proc/boot/libc.so
Как определить, какие разделяемые объекты необходимо включить в образ? Существуют несколько способов:
# ldd `which ping` /usr/bin/ping: libsocket.so.3 => /lib/libsocket.so.3 (0xb8200000) libc.so.3 => /usr/lib/ldqnx.so.2 (0xb0300000)
NEEDED:
# objdump -x `which ping` | grep NEEDED NEEDED libsocket.so.3 NEEDED libc.so.3
Программе ping необходимы библиотеки libsocket.so.3
и libc.so.3
. Чтобы определить, какие компоненты требуются этим библиотекам, необходимо рекурсивно выполнить утилиту objdump:
# objdump -x /lib/libsocket.so.3 | grep NEEDED NEEDED libc.so.3 # objdump -x /lib/libc.so.3 | grep NEEDED
Совместно используемому объекту libsocket.so.3
требуется только объект libc.so.3
, которому не требуются никакие объекты.
# DL_DEBUG=libs ping 10.42.110.235 load_object: attempt load of libsocket.so.3 load_elf32: loaded lib at addr b8200000(text) b822bccc(data) dlopen("nss_files.so.0",513) load_object: attempt load of nss_files.so.0 dlopen: Library cannot be found dlopen("nss_dns.so.0",513) load_object: attempt load of nss_dns.so.0 dlopen: Library cannot be found
Дополнительную информацию о значениях переменной DL_DEBUG см. в описании функции dlopen().
Чтобы выполнять программы несколько раз, необходимо присваивать им атрибут [data=copy]
. Чтобы применить атрибут ко всем программам, поместите его в отдельную строку перед списком программ. Если этот атрибут задан, сегмент данных программы копируется перед использованием, что предотвращает его перезапись во время первого выполнения программы.
В системах с несколькими консолями или последовательными портами можно выполнять командный интерпретатор на каждом из них. Для этого включите в файл построения загрузочного образа следующие строки:
[+script] .script = {# здесь запускаются все остальные необходимые драйверыdevc-con -e -n4 &reopen /dev/con1[+session] esh &reopen /dev/con2[+session] esh &...
В этом коде выполняются следующие действия:
Важно запускать командный интерпретатор в фоновом режиме (указывая символ &
) — в противном случае интерпретация сценария приостанавливается до тех пор, пока командный интерпретатор не завершает работу!
В общем случае этот метод позволяет запускать на консолях любые программы (т.е. не только командный интерпретатор).
Чтобы выполнить аналогичное действие на последовательных портах, запустите драйвер devc-ser8250 и перенаправьте стандартные потоки ввода, вывода и ошибок в каждый порт (например, /dev/ser1
, /dev/ser2
). После перенаправления запустите нужную программу (в фоновом режиме!).
Директива [+session]
объявляет программу лидером сеанса (в соответствии со стандартом POSIX) — обычно это не требуется при запуске обычных программ.
Можно выполнять команду reopen над любым устройством неограниченное количество раз — например, запустить программу на /dev/con1
, далее — командный интерпретатор на /dev/con2
, а затем — еще одну программу на /dev/con1
:
[+script] .script = {...reopen /dev/con1prog1 &reopen /dev/con2[+session] esh &reopen /dev/con1prog2 &...
Чтобы создать каталог /tmp
на диске в ОЗУ, можно включить в файл построения загрузочного образа следующую строку:
[type=link] /tmp = /dev/shmem
В пространстве путевых имен менеджера процессов создается каталог /tmp
, который является символьной ссылкой на каталог /dev/shmem
. Поскольку объекты общей памяти хранятся в каталоге /dev/shmem
, эта команда фактически позволяет создавать файлы на диске в ОЗУ.
Следует иметь в виду, что строка с атрибутом символьной ссылки ([type=link]
) должна находиться вне файлов сценария и загрузки, поскольку указывает утилите mkifs, что необходимо создать ссылку, а не "настоящий" файл.
В этом конфигурационном файле выполняется минимальный набор действий для запуска командного интерпретатора на первом последовательном порте:
[virtual=ppcbe,srec] .bootstrap = {startup-rpx-lite -Dsmc1.115200.64000000.16PATH=/proc/boot procnto-800}[+script] .script = {devc-serppc800 -e -F -c64000000 -b115200 smc1 &reopen[+session] PATH=/proc/boot esh &}[type=link] /dev/console=/dev/ser1[type=link] /usr/lib/ldqnx.so.2=/proc/boot/libc.solibc.so[data=copy]devc-serppc800esh# перечисление программ, которые требуется запускать# с помощью командного интерпретатора: echo, ls, pidin и др...echolspidincatcp
Рассмотрим готовый файл построения загрузочного образа, в котором запускается файловая система флеш-памяти:
[virtual=x86,bios +compress] .bootstrap = {startup-biosPATH=/proc/boot:/bin procnto}[+script] .script = {devc-con -e -n5 &reopen /dev/con1devf-i365sl -r -b3 -m2 -u2 -t4 &waitfor /fs0p0[+session] TERM=qansi PATH=/proc/boot:/bin esh &}[type=link] /tmp=/dev/shmem[type=link] /bin=/fs0p0/bin[type=link] /etc=/fs0p0/etclibc.so[type=link] /usr/lib/ldqnx.so.2=/proc/boot/libc.solibsocket.so[data=copy]devf-i365sldevc-conesh
В файле .bootstrap
, который находится в файле построения загрузочного образа, указаны обычные модули startup-bios и procnto (программа запуска и ядро). Обратите внимание, что переменная окружения PATH указывает не только на каталог /proc/boot
, но и на каталог /bin
, который создан с помощью атрибута [type=link]
и является ссылкой на путь к файловой системе флеш-памяти /fs0p0/bin
.
В файле .script
мы запустили драйвер консоли с пятью консолями, перенаправили стандартные потоки ввода, вывода и ошибок в консоль /dev/con1
и запустили драйвер файловой системы флеш-памяти devf-i365sl. Рассмотрим его командно-строковые параметры:
Драйвер devf-i365sl автоматически монтирует раздел флеш-памяти как /fs0p0
. Обратите внимание на символьные ссылки, которые созданы в менеджере процессов в конце файла построения загрузочного образа:
[type=link] /bin=/fs0p0/bin[type=link] /etc=/fs0p0/etc
В результате формируются каталоги /bin
и /etc
, которые ссылаются на файловую систему флеш-памяти.
В этом примере мы рассмотрим файловую систему для вращающихся накопителей. Обратите внимание на разделяемые библиотеки, которые необходимо включить в образ:
[virtual=x86,bios +compress] .bootstrap = {startup-biosPATH=/proc/boot:/bin LD_LIBRARY_PATH=/proc/boot:/lib:/dll procnto}[+script] .script = {pci-bios &devc-con &reopen /dev/con1# драйверы дисковdevb-eide blk cache=2m,automount=hd0t79:/,automount=cd0:/cd &# ожидание создания каталога bin для выполнения остальных командwaitfor /x86 10# несколько стандартных серверовpipe &mqueue &devc-pty &# запуск основного командного интерпретатора[+session] esh &}# /tmp указывает на область общей памяти[type=link] /tmp=/dev/shmem# перенаправление консольных сообщений[type=link] /dev/console=/dev/ser1# программам необходимо, чтобы компоновщик среды выполнения (ldqnx.so)# находился в фиксированном месте[type=link] /usr/lib/ldqnx.so.2=/proc/boot/libc.so# для поддержки жестких дисков[type=link] /usr/lib/libcam.so.2=/proc/boot/libcam.so# символьные ссылки для bin, dll и lib (файлы в /x86 с devb-eide)[type=link] /bin=/x86/bin[type=link] /dll=/x86/lib/dll[type=link] /lib=/x86/lib# совместно используемая C-библиотека (которая также содержит компоновщика среды выполнения)libc.so# на случай, если кому-то необходимо поддержка вещественных чисел, а в нашем процессоре отсутствует# математический сопроцессорfpemu.so.2# разделяемые библиотеки для доступа к жестким дискамlibcam.soio-blk.so# для файловой системы QNX 4cam-disk.sofs-qnx4.so# для файловой системы UDF и шины PCIcam-cdrom.sofs-udf.sopci-bios# копирование сегментов кода и данных всех нижеперечисленных исполняемых файлов[data=copy]# драйвер консоли, командный интерпретатор и др.eshdevb-eidedevc-con
![]() | В этой версии ЗОСРВ «Нейтрино» невозможно использовать эмулятор математического сопроцессора ( fpemu.so) в статически компонуемых программах. |
Файл построения загрузочного образа содержит строку с командой запуска драйвера devb-eide:
devb-eide blk cache=2m,automount=hd0t79:/automount=cd0:/cd &
В этой строке указано, что драйвер devb-eide должен запуститься и передать строку, которая начинается с cache=
и завершается в конце команды (без амперсанда), библиотеке блочного ввода/вывода ( io-blk.so). Библиотека проверяет переданную командную строку, запускается с 2-мегабайтным кешем (cache=2m
), а затем автоматически монтирует раздел hd0t79 (первый раздел файловой системы) под путевым именем /hd
и CD-ROM под путевым именем /cd
.
После запуска драйвера нам необходимо дождаться, когда он получит доступ к диску, и выполнить операции монтирования:
waitfor /ppcbe/bin
Эта строка ждет создания имени /ppcbe/bin
в пространстве путевых имен (мы предполагаем, что в системе имеется форматированный жесткий диск, который содержит корректную файловую систему с копией target-каталога (на который ссылается переменная окружения KPDA_TARGET) в корневом каталоге.
Теперь у нас имеется готовая файловая система со всеми необходимыми программами, которые мы можем запускать (например, сервер pipe).
В списке совместно используемых объектов указаны файлы .so
, которые требуются драйверам и файловой системе.
В этом разделе показан пример файла построения загрузочного образа, который запускает драйвер Ethernet, стек TCP/IP и сетевую файловую систему:
[virtual=armle,elf +compress] .bootstrap = {startup-abc123 -vvvPATH=/proc/boot procnto}[+script] .script = {devc-ser8250 -e -b9600 0x1d0003f8,0x23 &reopen# запуск сервера PCI.pci-abc123 &waitfor /dev/pci# сетевые драйверы и файловые системыio-pkt-v4 -dtulip-abc123 name=enif_up -p en0ifconfig en0 10.0.0.1fs-nfs3 10.0.0.2:/armle/ / 10.0.0.2:/etc /etc &# ожидание создания каталога bin для выполнения остальных командwaitfor /usr/bin# несколько стандартных серверовpipe &mqueue &devc-pty &[+session] sh &}# /tmp указывает на область общей памяти[type=link] /tmp=/dev/shmem# перенаправление консольных сообщений[type=link] /dev/console=/dev/ser1# программам необходимо, чтобы компоновщик среды выполнения (ldqnx.so)# находился в фиксированном месте[type=link] /usr/lib/ldqnx.so.2=/proc/boot/libc.so# Совместно используемая C-библиотека (которая также содержит компоновщика среды выполнения)libc.so# если кому-то требуется поддержка вещественных чисел...fpemu.so.2# для доступа к файлам по сетиdevn-tulip-abc123.so# библиотека сокетовlibsocket.so[data=copy]# сетевые программыdevc-ser8250io-pkt-v4fs-nfs3
![]() | В этой версии ЗОСРВ «Нейтрино» невозможно использовать эмулятор математического сопроцессора ( fpemu.so.2) в статически компонуемых программах. |
Вышеуказанный файл построения загрузочного образа очень похож на предыдущий файл сборки для диска; их основное различие заключается в том, что вместо запуска дисковой файловой системы с помощью менеджера devb-eide мы запустили сетевые драйверы с помощью менеджера io-pkt-v4. Параметр -d задает сетевой драйвер, который необходимо загрузить.
После запуска менеджера сети необходимо приостановить интерпретацию файла сценария до тех пор, пока драйверы не станут готовыми к работе. Для этой цели используется команда waitfor /dev/socket — она ожидает окончания инициализации менеджера сети. Затем команда ifconfig en0 10.0.0.1 задает IP-адрес интерфейса.
Далее запускается модуль файловой системы NFS fs-nfs3 с параметрами, которые монтируют файловую систему узла 10.0.0.2
в две точки: KPDA_TARGET — в каталог /
, а /etc
— в каталог /etc
.
Поскольку монтирование файловой системы удаленного узла занимает некоторое время, в файле построения загрузочного образа указывается еще одна команда waitfor, которая ожидает корректного завершения монтирования (мы предполагаем, что в файловой системе удаленного узла имеется каталог ${KPDA_TARGET}/armle/bin
; поскольку мы смонтировали каталог KPDA_TARGET в каталог /
, команда waitfor фактически ожидает создания каталога armle/bin
в каталоге KPDA_TARGET удаленного узла).
В этом разделе мы рассмотрим отличия файлов построения загрузочного образа, которые предназначены для конкретных семейств процессоров, от вышеуказанных общих файлов. Поскольку в ЗОСРВ «Нейтрино» почти весь код, специфичный для процессоров и платформ, находится в ядре и startup-*, для перехода с одной платформы на другую (например, с x86 со стандартной BIOS на отладочную плату PowerPC 800) требуется минимум изменений.
Первое очевидное действие, которое необходимо выполнить — указать в файле построения загрузочного образа процессор, для которого он предназначен. Это несложно — в строке [virtual=...]
достаточно заменить значение x86 на armle, mipsbe, ppcbe или e2kle.
Процессор | Атрибут |
---|---|
ARM (с прямым порядком байт) | [virtual=armle,binary] |
MIPS (с обратным порядком байт) | [virtual=mipsbe,elf] |
PPC (с обратным порядком байт) | [virtual=ppcbe,openbios] |
Еще одно отличие заключается в том, что startup-* связана не только с семейством процессоров, но и с платой, на которой работает конкретный процессор. Если не используется платформа x86 со стандартной BIOS, следует заменить команду startup-bios на одну из многочисленных штатных модулей startup-*.
Чтобы узнать, какие startup-* поддерживаются на текущий момент, обратитесь к следующим источникам:
boards
каталога рабочий_каталог_bsp/src/hardware/startup
В вышеприведенных примерах поддерживается семейство микросхем последовательных портов 8250. Одни платформы, отличные от x86, также поддерживают семейство 8250, а в других используются собственные микросхемы последовательных портов.
Подробную актуальную о наших драйверах последовательных портов см. в описании драйверов devc-*.
Предыдущий раздел: перейти