Программирование ARM Загрузчик U-Boot Thu, November 21 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.


Загрузчик U-Boot Печать
Добавил(а) microsin   

U-Boot на сегодняшний день является основным загрузчиком Linux для встраиваемых систем. Он доступен для большого количества архитектур, включая x86, ARM, MIPS, 68k, SuperH, PPC, RISC-V, MicroBlaze, Blackfin и Nios.

Загрузчик U-Boot в процессе запуска Linux проходит несколько стадий запуска. Самая первая часть запускаемого кода находится по адресу перехода по сбросу (reset vector), и эта часть кода обычно находится в ПЗУ процессора (on-chip BootROM) или BIOS. На этой стадии происходит минимальная инициализация железа процессора, и происходит переход к следующей стадии загрузки.

[User Bootloader]

Следующая стадия загрузки - пользовательский код загрузчика (user bootloader). Это первый код, которым может управлять пользователь. Он производит все необходимые действия (в частности, здесь обычно реализована процедура запуска перепрошивки) и далее запускает код ядра (Linux kernel). Код ядра после своей загрузки запускает все необходимые процессы пространства пользователя.

SPL - Secondary Program Loader. User bootloader в свою очередь состит из нескольких частей. Первая часть называется SPL (сокращение от Secondary Program Loader). Функция SPL заключается в запуске итерактивного shell-а по запросу пользователя, либо в запуске ядра Linux, если этого запроса не было.

Интерфейс входа в SPL может выглядеть следующим образом:

U-Boot SPL 2018.01-00002-g9aa111a004 (Jan 20 2018 - 12:45:29)
Trying to boot from MMC1
U-Boot 2018.01-00002-g9aa111a004 (Jan 20 2018 - 12:45:29 -0600)
CPU : AM335X-GP rev 2.1 I2C: ready DRAM: 512 MiB Reset Source: Global warm SW reset has occured. Reset Source: Power-on reset has occured. MMC: OMAP SD/MMC: 0, OMAP SD/MMC: 1
Model: BeagleBoard.org PocketBeagle Net: usb_ether Press SPACE to abort autoboot in 2 seconds =>

В приглашении командной строки => доступны множество функций - запуск дальнейшей загрузки определенного ядра, манипуляции с деревом устройств (device tree), работа с переменными окружения, просмотр и модификация ячеек адресного пространства и многое другое. Поскольку поведение U-Boot может быть автоматизировано настройками, пользователю не обязательно нужно каждый раз вводить управляющие команды, чтобы загрузить рабочую систему Linux с нужными параметрами.

Основные функции SPL:

• Собирается из того же исходного кода, что и U-Boot.
• Значительно уменьшенный размер и набор функций.
• Используется для инициализации системы и запуска U-Boot или Linux.

TPL - Tertiary Program Loader.

• Собирается из того же исходного кода, что и U-Boot.
• Даже меньше, чем SPL.
• Используется редко, только на очень ограниченных по ресурсам системах (например OneNAND).

[Назначение файлов и папок исходного кода U-Boot]

README. Общая документация по проекту U-Boot. Здесь приведено описание текущего состояния проекта, ссылки на исходный код, указания по выбору конфигурации и компиляции кода, описание опций компиляции (CONFIG_xxxx, CFG_xxxx, FDT_xxxx, I2C_xxxx и т. п.), поддерживаемые форматы образов, указания по портированию Linux на систему с использованием U-Boot и много другой полезной информации.

configs. В директории configs содержатся все доступные конфигурации, одну из которых можно выбрать для сборки под определенную процессорную платформу. Это файлы, имя которых оканчивается на суффикс _defconfig. Компиляция под выбранную платформу осуществляется командой "make < имя_платы>_defconfig". Пример для модуля TQM823L:

$ cd u-boot
$ make TQM823L_defconfig

[Интерактивный шелл U-Boot]

Могут быть выбраны 2 варианта шелла: оригинальный старый (у которого нет имени) и HUSH (шелл с расширенным набором функций). HUSH изначально был портирован их BusyBox, и этот вариант для большинства ситуаций является лучшим выбором. Он работает наподобие bourne shell, поддерживает постоянное хранилище переменных окружения и скрипты, содержит встроенную систему подсказок по командам.

Командная строка HUSH позволяет выполнять множество низкоуровневых сервисных функций, таких как сравнение областей памяти, копирование областей памяти и вычисление контрольных сумм блоков памяти (cmp, cp, crc32), получение информации об устройствах (coninfo), редактирование переменных окружения и управления ими (editenv, env, printenv, saveenv, setenv, setexpr), стирание памяти FLASH (erase), получение информации о памяти FLASH (flinfo, nand), запуск кода приложения по указанному адресу (go), вывод содержимого памяти и её изменение (md, mm, mw), загрузка через последовательные интерфейсы и TFTP (loadb, loads, loadx, loady, tftp), управление разделами (chpart, mtdparts), управление загрузкой (boot, bootd, bootelf, bootm, bootp, bootvx, nboot, nfs), сброс и перезагрузка (reset), запуск определенных в переменных окружения команд (run) и многое другое.

Интерактивный диалог команд с выводом подсказки может выглядеть следующим образом:

=> help
?         - alias for 'help'
base      - print or set address offset
bdinfo    - print Board Info structure
boot      - boot default, i.e., run 'bootcmd'
bootd     - boot default, i.e., run 'bootcmd'
bootelf   - Boot from an ELF image in memory
bootm     - boot application image from memory
bootp     - boot image via network using BOOTP/TFTP protocol
bootvx    - Boot vxWorks from an ELF image
chpart    - change active partition
cmp       - memory compare
coninfo   - print console devices and information
cp        - memory copy
crc32     - checksum calculation
echo      - echo args to console
editenv   - edit environment variable
env       - environment handling commands
erase     - erase FLASH memory
exit      - exit script
false     - do nothing, unsuccessfully
flinfo    - print FLASH memory information
go        - start application at address 'addr'
help      - print command description/usage
iminfo    - print header information for application image
itest     - return true/false on integer compare
loadb     - load binary file over serial line (kermit mode)
loads     - load S-Record file over serial line
loadx     - load binary file over serial line (xmodem mode)
loady     - load binary file over serial line (ymodem mode)
loop      - infinite loop on address range
md        - memory display
mm        - memory modify (auto-incrementing address)
mtd       - MTD utils
mtdparts  - define flash/nand partitions
mw        - memory write (fill)
nand      - NAND sub-system
nboot     - boot from NAND device
nfs       - boot image via network using NFS protocol
nm        - memory modify (constant address)
otp       - otp sub-system:
printenv  - print environment variables
protect   - enable or disable FLASH write protection
reset     - Perform RESET of the CPU
run       - run commands in an environment variable
saveenv   - save environment variables to persistent storage
setenv    - set environment variables
setexpr   - set environment variable as the result of eval expression
showvar   - print local hushshell variables
sleep     - delay execution for some time
source    - run script from memory
test      - minimal test like /bin/sh
tftp      - boot image via network using TFTP protocol
tftpboot  - boot image via network using TFTP protocol
tftpput   - TFTP put command, for uploading files to a server
true      - do nothing, successfully
ubi       - ubi commands
ubifsload - load file from an UBIFS filesystem
ubifsls   - list files in a directory
ubifsmount- mount UBIFS volume
ubifsumount- unmount UBIFS volume
upimgtar  - update kernel and rootfs by tar format on luna platform
upvmimg   - update kernel and rootfs by vmimg format on luna platform
version   - print monitor, compiler and linker version

Можно запрашивать подсказку как по всем командам, так и по конкретной команде:

=> help echo
echo - echo args to console
Usage:
echo [args..]
    - echo args to console; \c suppresses newline
=> help bdinfo bdinfo - print Board Info structure Usage: bdinfo

У некоторых команд есть субкоманды, например:

=> help ubi
ubi - ubi commands
Usage: ubi detach - detach ubi from a mtd partition ubi part [part] [offset] - Show or set current partition (with optional VID header offset) ubi info [l[ayout]] - Display volume and ubi layout information ubi check volumename - check if volumename exists ubi create[vol] volume [size] [type] [id] [--skipcheck] - create volume name with size ('-' for maximum available size) ubi write[vol] address volume size - Write volume from address with size ubi write.part address volume size [fullsize] - Write part of a volume from address ubi read[vol] address volume [size] - Read volume to address with size ubi remove[vol] volume - Remove volume ubi skipcheck volume on/off - Set or clear skip_check flag in volume header [Legends] volume: character name size: specified in bytes type: s[tatic] or d[ynamic] (default
=dynamic)

echo. Команда echo полезна для печати текста. Она не интерпретирует последовательности управления (за исключением \\c, подавляющего newline):

=> echo hello world
hello world
=> echo foo\\c ; echo bar
foobar

bdinfo. Команда bdinfo выводит информационную структуру железа (адреса и размер памяти, MAC и IP адрес, скорость обмена по последовательному интерфейсу консоли).

=> bdinfo
boot_params = 0x8f735408
memstart    = 0x80000000
memsize     = 0x10000000
flashstart  = 0x00000000
flashsize   = 0x00000000
flashoffset = 0x00000000
ethaddr     = 00:E0:4C:86:70:01
IP addr     = 192.168.1.3
baudrate    = 115200 bps
relocaddr   = 0x8ff70000
reloc off   = 0x0c370000

[Команды доступа к памяти]

Команды md, mm, mw полезны для чтения/записи ячеек памяти и регистров.

md. С помощью суффиксов команда md поддерживает выбор ширины доступа к данным - byte/word/long/quad (.b, .w, .l, .q), по умолчанию ширина long, т. е. 32 бита (md == md.l). Поддерживается вывод заданного количества элементов данных (по умолчанию 0x40), например:

=> md 0x80000000
80000000: 10000001 40804800 2408fff0 3c098040    ....@.H.$...< ..@
80000010: 0128e824 27bdff54 03a8e824 03a0d021    .(.$'..T...$...!
80000020: 240a0400 03aae823 03a8e824 03a0f021    $......#...$...!
80000030: 03404021 ad000000 0109082a 1420fffd    .@@!.......*. ..
80000040: 25080004 af5d009c 3c1983c0 27396e54    %....]..< ...'9nT
80000050: 0320f809 00000000 00002021 3c1983c1    . ........ !< ...
80000060: 27395d90 03200008 0000f821 00000000    '9].. .....!....
80000070: 40027800 00021382 30420001 10400009    @.x.....0B...@..
80000080: 00000000 4008a000 2409fffd 01094024    ....@...$.....@$
80000090: 4088a000 35080002 4088a000 03e00008    @...5...@.......
800000a0: 00000000 40088001 00082402 30840007    ....@.....$.0...
800000b0: 20840001 00082cc2 30a50007 20a50001     .....,.0... ...
800000c0: 00083582 30c60007 20c60006 24080001    ..5.0... ...$...
800000d0: 00c53020 00c83004 70c41002 00a81804    ..0 ..0.p.......
800000e0: 3c048000 00822820 00804021 bd000000    < .....( ..@!....
800000f0: 0000000f 21080010 0105082a 1420fffb    ....!......*. ..

Если было указано количество выводимых элементов памяти, то оно впоследствии запоминается как умолчание.

=> md.b 0x80000000 0x8
80000000: 10 00 00 01 40 80 48 00                            ....@.H.
=> md.l 0x80000000
80000000: 10000001 40804800 2408fff0 3c098040    ....@.H.$...< ..@
80000010: 0128e824 27bdff54 03a8e824 03a0d021    .(.$'..T...$...!

Простое нажатие Enter после команды md позволяет последовательно выводить адреса блоков с автоматическим инкрементом адреса:

=> md 0x80000000 8
80000000: 10000001 40804800 2408fff0 3c098040    ....@.H.$...< ..@
80000010: 0128e824 27bdff54 03a8e824 03a0d021    .(.$'..T...$...!
=>
80000020: 240a0400 03aae823 03a8e824 03a0f021    $......#...$...!
80000030: 03404021 ad000000 0109082a 1420fffd    .@@!.......*. ..
=>
80000040: 25080004 af5d009c 3c1983c0 27396e54    %....]..< ...'9nT
80000050: 0320f809 00000000 00002021 3c1983c1    . ........ !< ...

mm, nm. Эти команды удобны для интерактивной модификации содержимого памяти и регистров. К ним применимы те же свойства, что и к командам md/mw. Команда mm автоматически инкрементирует адрес, а команда nm этого не делает. Клавиша 'q' выполнит возврат обратно в командную строку U-Boot, а клавиша '-' выполнит возврат к предыдущему адресу. Нажатие Enter без ввода значения пропустит текущий адрес.

=> mm 0x4804c134
4804c134: ffffffff ? fe1fffff
4804c138: f0002300 ?
4804c13c: 00000000 ? 00400000
4804c140: 00000000 ? q
=>

cp, cmp. Команда cp позволяет копировать области памяти, а cmp сравнивать их. К этим командам применимы те же свойства, что и к командам md/mw.

[U-Boot environment и команды скриптов]

Environment, или переменные окружения, представляет собой хранилище пар ключ-значение. В нем могут содержаться настроенные конфигурационные значения и скрипты (последовательности выполняемых команд). Окружение по умолчанию встроено в двоичный код U-Boot. Опциональные пользовательские значения могут загружаться из энергонезависимой памяти. Переменные окружения можно изменять, можно их значения сделать постоянными (persistent, т. е. сохраненными в энергонезависимой памяти, чтобы они восстанавливались при последующей перезагрузке). Копия значений переменных окружения находится в RAM, и к ним можно обращаться по имени (ключу) в командах и скриптах.

Поведение команд управления окружением U-Boot очень похоже на поведение аналогичных команд Linux [4].

printenv, env print, echo. Эти команды предназначены для печати переменных окружения. Команда printenv и является псевдонимом (alias) команды env print.

=> env print
_updev=tftp ${tftp_base} ${ubi_device_img_name} && nand erase ${fl_ubidevice} ${fl_ubidevice_sz} \
       && nand write  ${fileaddr} ${fl_ubidevice} ${filesize} && run set_comm0
_updev_bk=ubi read ${tftp_base} ubi_Config && ubi detach && setenv tftp_tmp ${tftp_base} \
       && setenv tftp_base ${tftp_base_bk} && run _updev && setenv tftp_base ${tftp_}
baudrate=115200
boot_by_commit=if itest.s ${sw_commit} == 0;then run set_act0;run ub0;else run set_act1;run ub1;fi
boot_by_tryactive=if itest.s ${sw_tryactive} == 0;then setenv sw_tryactive 2;setenv sw_active 0; \
      saveenv;run en_wdt;run ub0;else setenv sw_tryactive 2;setenv sw_active i
bootargs=console=ttyS0,115200
bootargs_base=console=ttyS0,115200
bootcmd=if itest.s ${sw_tryactive} == 2; then run boot_by_commit;else run boot_by_tryactive;fi
bootdelay=1
bootloader_crc=a1bbb412
...
Environment size: 6299/131067 bytes
=>
=> env print serverip
serverip=192.168.1.1
=> printenv serverip 
serverip=192.168.1.1
=> echo "$serverip"
192.168.1.1

setenv, askenv, editenv. Эти команды предназначены для изменения переменных окружения, и представляют собой legacy-псевдонимы для команд env set, env ask, env edit.

=> env set foo bar
=> env print foo
foo=bar
=> env ask quux "Set quux to ?" Set quux to ? 1234 => env print quux quux=1234
=> env edit quux edit: 24 => env print quux quux=24

Удаление переменных окружения. Установка переменной окружения в пустое значение удалит её из окружения.

=> env set foo bar
=> env print foo
foo=bar
=> env set foo
=> env print foo
## Error: "foo" not defined

saveenv. По умолчанию любые текущие изменения переменной действуют только до перезагрузки, потому что это изменение происходит в текущей копии переменной, находящейся в RAM. Команда saveenv позволит сохранить текущее измененное значение переменной в энергонезависимую память, благодаря чему она восстановится при следующей загрузке.

=> env set foo bar
=> env print foo
foo=bar
=> reset
## Rebooting...
=> env print foo
## Error: "foo" not defined
=> env set foo bar
=> saveenv
=> reset
## Rebooting...
=> env print foo
foo=bar

run. Команда run позволяет запускать скрипты, настроенные в переменных окружения. Скрипт по сути это просто строка текста, состоящая из команд U-Boot. Отдельные команды в этой строке могут быть отделены символом точки с запятой ';'. Эти команды выполняются последовательно, друг за другом. Имейте в виду, что ; игнорирует возвращаемое значение предыдущей команды. Также можно использовать и другие операторы командной строки: |, &, ||, && [].

=> env set foo 'echo hello'
=> run foo
hello
=> env set foo 'echo hello ; echo world' => run foo hello world

Экранирование символов и расширение переменной. Специальные символы, предназначенные для операторов и для расширения переменной, могут быть экранированы обычным образом с помощью обратного слеша '\'. Вот пример с экранированием символа '$', который расширяет значение переменной:

=> env set foo bar
=> env set quux echo $foo
=> run quux
bar
=> env print quux
quux=echo bar
=> env set quux echo \$foo => env print quux quux=echo $foo => env set quux 'echo $foo' => env print quux quux=echo $foo

Специальные переменные. Могут быть определены некоторые переменные для, обладающие зарезервированным назначением. Пример таких переменных:

ver Версия U-Boot.

sddin, stdout, stderr Перенаправление STFIO, см. также команду coninfo.

=> coninfo
List of available devices:
serial   00000003 IO stdin stdout stderr 
eserial0 00000003 IO

loadadr. Адрес загрузки по умолчанию.

filesize. Размер загружаемого файла.

bootargs. Аргументы загрузки Linux, передаваемые в её командную строку.

=> echo $bootargs
console=ttyS0,115200

bootcmd. Команда загрузки по умолчанию (см. команды boot и autoboot).

=> echo $bootcmd
if itest.s ${sw_tryactive} == 2; then run boot_by_commit;else run boot_by_tryactive;fi

preboot. Скрипт, выполняемый перед autoboot.

ipaddr, netmask, serverip, gatewayip. Настройки сети.

ethaddr, eth1addr, ... MAC-адрес Ethernet.

setexpr. Команда setexpr это многофункциональный инструмент для манипуляции окружением. Она позволяет загрузить содержимое памяти в переменную, поддерживает арифметические операции над переменными и надо памятью (AND, OR, XOR, +, -, *, /, MOD), а также базовые regex-манипуляции над строками и переменными.

=> md 0x9ff4e000 1
9ff4e000: ea0000b8
=> setexpr foo *0x9ff4e000
=> env print foo
foo=ea0000b8
=> env set foo 1 ; env set bar 2 => setexpr baz $foo + $bar => env print baz baz=3
=> setexpr foo gsub ab+ x "aabbcc" => env print foo foo=axcc

[Условные выражения и циклы shell]

Команды true/false. U-Boot поддерживает обработку возвращаемых значений из команд и скриптов. Поддерживаются также автоматические переменные (переменная $? возвратит результат последней выполненной команды). Команды true и false предназначены для возврата результата успеха или неудачи, они установят результат последней выполненной команды.

По традиции программирования успешный результат это значение 0, а ненулевое значение соответствует неудачному результату. Команда true определена для удачного результата, а команда false для неудачного, поэтому их значения довольно неожиданно становятся обратными: true это значение 0, а false это значение 1:

=> true
=> echo $?
0
=> false
=> echo $?
1

Условные выражения. Поддерживаются if, операторы ||, &&. Следует отметить, что не поддерживается "if ! foo ; then ... fi", как обходной маневр вместо этого следует использовать "if foo ; then false ; else ... fi".

=> if true ; then echo "hello" ; else echo "bye" ; fi
hello
=> false || echo "false!"
false!
=> env set foo 'true && echo "true!"' => run foo true!

test. Оболочка HUSH поддерживает минимальную версию команды test.

=> env set i 4
=> test $i -lt 5
=> echo $?
0
=> env set i 6
=> test $i -lt 5
=> echo $?
1
=> if test $i -lt 5 ; then echo "Less than 5" ; \
   else echo "More than 5" ; fi
More than 5

for. Пример цикла for:

=> for i in a b c d ; do echo "$i" ; done
a
b
c
d

while. Пример бесконечного цикла while, остановить работу которого можно комбинацией клавиш Ctrl+C:

=> while true ; do echo hello ; done
hello
hello
hello
hello
...
# Ctrl+C
=>

[Команды загрузки данных]

U-Boot поддерживает загрузку из хранилищ различных типов:

• SD/MMC - командой mmc.
• USB - командой usb.
• SATA - командой sata.
• NAND - командой nand.
• ...

Поддерживается RAW-носитель и файловые системы:

• Универсальный доступ к файловой системе - команды ls, load.
• ExtFS - legacy-команды extls, extload.
• VFAT - legacy-команды fatls, fatload.
• UBI/UBIFS - команда ubi.
• ...

Squashfs [5] не поддерживается, однако делаются попытки её внедрения [6].

Пример загрузки с карты MMC:

=> mmc rescan
=> mmc part
Partition Map for MMC device 0 -- Partition Type: DOS
Part Start Sector Num Sectors UUID Type 1 8192 695008 1147c091-01 83 Boot
=> ls mmc 0:1 < DIR> 4096 . < DIR> 4096 .. 40 ID.txt ... => load mmc 0:1 $loadaddr ID.txt => md.b $loadaddr $filesize 82000000: 42 65 61 67 6c 65 42 6f 61 72 ... BeagleBoard.org 82000010: 44 65 62 69 61 6e 20 49 6d 61 ... Debian Image 201 82000020: 38 2d 30 31 2d 32 38 0a 8-01-28.

Загрузка из сети. U-Boot поддерживает только сетевой стек UDP (соединения TCP не поддерживаются).

• Поддерживается TFTP, NFS (через UDP), DHCP/BOOTP, ...
• ping - ICMP Echo.
• Команда tftp выполняет загрузку по TFTP (tftpput для выгрузки).
• dhcp - получение настроек от DHCP и загрузка файла.

Пример:

=> env set ethaddr 00:aa:bb:cc:dd:ee
=> env set ipaddr 192.168.1.30
=> env set netmask 255.255.255.0
=> env set serverip 192.168.1.1
=> ping $serverip
=> tftp $loadaddr $serverip:somefile
=> dhcp $loadaddr $serverip:somefile
30408.pts-4.0001NBB0203LZB4

Примечание: установка MAC-адреса необязательна, потому что вероятно это уже настроено в окружении U-Boot.

Загрузка через последовательный порт. Когда больше ничего нет, обычно для загрузки доступен UART. U-Boot поддерживает протоколы XMODEM, YMODEM, Srecord и kermit. Пример:

U-Boot> loady
< отправка файла по протоколу ymodem, например sb -T>
$ screen /dev/ttyUSB0 115200 => loady ctrl-a:exec !! sb -T yourbinary.bin

Или из другого шелла того же самого компьютера хоста:

$ screen -x -r -X exec \!\! sb -T yourbinary.bin

[Загрузка kernel]

Существует несколько поддерживаемых форматов образа.

(z)Image:

• Linux binary (с декомпрессором, распаковывающим код в RAM).
• Нет защиты от bitrot.
• Просто настраивает регистры и выполняет переход в образ.
• Опционально отдельное Device Tree.

uImage:

• Старый наследуемый формат.
• Обертка над произвольным бинарником (только над одним файлом).
• Контрольная сумма CRC32 и небольшое количество метаданных.
• Опционально отдельное Device Tree.

fitImage. Это современный формат, образ состоит из нескольких компонентов:

• Основан на Device Tree.
• Поддерживает несколько файлов.
• Конфигурируемый алгоритм контрольной суммы для каждого элемента.
• Поддержка цифровых подписей.

Для загрузки могут использоваться команды:

boot      - загрузка по умолчанию, например run 'bootcmd'
bootd    - то же самое
bootelf  - загрузка из образа ELF в память
booti     - загрузка образа ARM64
bootm   - загрузка образа приложения из памяти (автодетект формат: fitImage, uImage)
bootp    - загрузка образа через сеть с использованием протокола BOOTP/TFTP
bootvx   - загрузка vxWorks из образа ELF
bootz     - загрузка (z)Image

Пример:

=> help bootz
bootz - boot Linux zImage image from memory
Usage: bootz [addr [initrd[:size]] [fdt]] - boot Linux zImage stored in memory
The argument 'initrd' is optional... The optional arg ':size' allows specifying the size of RAW initrd.
When booting a Linux kernel which requires a flat device-tree a thitd argument is required which is the address of the device-tree blob. => env set bootargs console=tty0,115200 => load mmc 0:1 0x82000000 boot/zImage-4.9.82-ti-r102 9970640 bytes read in 673 ms (14.1 MiB/s) => load mmc 0:1 0x88000000 boot/dtbs/4.9.82-ti-r102/\ am335x-pocketbeagle.dtb 132769 bytes read in 180 ms (719.7 KiB/s) => bootz 0x82000000 - 0x88000000 ## Flattened Device Tree blob at 88000000 Booting using the fdt blob at 0x88000000 Loading Device Tree to 8ffdc000, end 8ffff6a0 ... OK
Starting kernel ...
[ 0.000000] Booting Linux on physical CPU 0x0 [ 0.000000] Linux version 4.9.82-ti-r102 \ (root@b2-am57xx-beagle-x15-2gb) (gcc version 6.3.0 20170516 (Debian 6.3.0-18) ) #1 SMP PREEMPT Thu Feb 22 01:16:12 UTC) [ 0.000000] CPU: ARMv7 Processor [413fc082] revision 2 (ARM7)

Device Tree. Это структура данных, описывающая оборудование (hardware, HW) устройства. Обычно она передается в OS, чтобы предоставить информацию топологии HW, которая не может быть детектирована или прочитана автоматически. Структура представляет собой нециклический граф, содержащий именованные узлы с их свойствами. Узлы могут содержать свойства и дочерние узлы.

Свойства представлены парами имя-значение. Свойства могут ссылаться на другие узлы с помощью так называемых phandle, где имя узла указывается в угловых скобках. Например, "< &L2>" это сылка на узел кэша L2. phandle могут использоваться для ссылки на узлы в любом месте Device Tree.

Подробнее про Device Tree см. Википедию [7].

Пример Device Tree:

/dts-v1/
#include "arm-realview-eb-mp.disi"
/ {
        model = "ARM RealView EB Cortex A9 MPCore";
[...]
        cpus {
                #address-cells = < 1>;
                #size-cells = < 0>;
                enable-method = "arm,realview-smp";
                A9_0: cpu@0 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a9";
                        reg = < 0>;
                        next-level-cache = < &L2>;
                };
[...]
        pmu: pmu@0 {
        interrupt-affinity = < &A9_0>, < &A9_1>, < &A9_2>, < &A9_3>
};        };

Пример fitImage:

/dts-v1/;
/ { description = "Linux kernel and FDT blob for sockit";
images { kernel@1 { description = "Linux kernel"; data = /incbin/("./arch/arm/boot/zImage"); type = "kernel"; arch = "arm"; os = "linux"; compression = "none"; load = < 0x00008000>; entry = < 0x00008000>; hash@1 { algo = "crc32"; }; }; fdt@1 { description = "Flattened Device Tree blob"; data = /incbin/("./arch/arm/boot/dts/socfpga....dtb"); type = "flat_dt"; arch = "arm"; compression = "none"; hash@1 { algo = "crc32"; }; }; };
configurations { default = "conf@1"; conf@1 { description = "Boot Linux kernel with FDT blob"; kernel = "kernel@1"; fdt = "fdt@1"; hash@1 { algo = "crc32"; }; }; }; };

Компиляция:

$ mkimage -f fit-image.its fitImage

Команды fitImage:

bootm $fitimageaddr - boot fitImage/uImage.
iminfo - печать информации образа.
imxtract - распаковка файла из fitImage/uImage.

=> iminfo $loadaddr
## Checking Image at 0x82000000 ... FIT image found FIT description: Linux kernel and FDT blob for am335x-pocketimage Created: 2018-09-03 0:46:36 UTC Image 0 (kernel@1) Description: Linux kernel (Mon Sep 3 02:46:36 CEST 2013) Created: 2018-09-03 0:46:36 UTC Type: Kernel Image Compression: uncompressed Data Start: 0x02000154 Data Size: 5565328 bytes = 5.4 MiB Architecture: ARM OS: Linux Load Address: 0x80008000 Entry Point: 0x80008000 Hash algo: crc32 Hash value: 1a1062ee ... => imxtract $loadaddr kernel@1 0x8a000000 ## Copying 'kernel@1' subimage from FIT image at 82000000 ... crc32+ Loading part 0 ... OK => md 0x8a000000 8a000000 e1a00000 e1a00000 e1a00000 e1a00000 ................ 8a000010 e1a00000 e1a00000 e1a00000 e1a00000 ................ 8a000020 e1a00005 016f2818 00000000 00667230 .....{o.....OrV.

Команда fdt. Команда fdt позволяет выполнять следующие действия:

fdt addr - указывает U-Boot, где находится FDT.
fdt resize - добавляет к FDT дополнительное пространство.
fdt print - печатает путь FDT.
fdt set- добавляет или изменяет элемент FDT.

=> load mmc 0:1 0x88000000 boot/dtbs/4.9.82-ti-r102/\
        am335x-pocketbeagle.dtb
132769 bytes read in 180 ms (719.7 KiB/s)
=> fdt addr 0x88000000
=> fdt resize
=> fdt print /chosen
chosen {
        stdout-path = "/ocp/serial@44e09000";
};
=> fdt set /chosen/ foo bar
=> fdt resize
=> fdt print /chosen
chosen {
        foo = "bar";
        stdout-path = "/ocp/serial@44e09000";
};
=> bootz = 0x82000000 - 0x88000000

[Другие команды U-Boot]

gpio. Эта команда полезна для переключения уровня выходов GPIO и чтения входов GPIO.

gpio input - чтение уровня на входе GPIO.
gpio set - установит уровень лог. 1 на выходе GPIO.
gpio clear - установит уровень лог. 0 на выходе GPIO.
gpio toggle - переключит уровень на выходе GPIO в противоположное значение.

=> gpio input 45
gpio: pin 45 (gpio 45) value is 1
=> echo $?
1
=> gpio set 53
gpio: pin 53 (gpio 53) value is 1

i2c. Позволяет обращаться к шине I2C.

i2c bus - выведет список доступных шин I2C.
i2c dev - выберет шину I2C.
i2c md - прочитает регистры из устройства I2C.
i2c mv - запишет регистры в устройстве I2C.
i2c probe - опрос устройств на I2C.
i2c speed - установит скорость шины I2C.

=> i2c dev 2
Setting bus to 2
=> i2c probe
Valid chip addresses: 1C
=> i2c md 0x1c 0x0 0x8
0000: 00 41 ac 01 fc 7f 10 00     .A......

Дополнительную информацию по командам U-Boot см. по ссылкам [2, 3].

[Компиляция U-Boot]

Исходный код доступен по протоколам Git и HTTP в следующих источниках.

• Git master: http://git.denx.de/?p=u-boot.git;a=summary
• Github: https://github.com/u-boot/u-boot
• Custodian subtrees: http://git.denx.de/?p=u-boot.git;a=forks

$ git clone git://git.denx.de/u-boot.git
$ cd u-boot
$ export CROSS_COMPILE=arm-linux-gnueabihf- # опциональная настройка кросс-компилятора
$ make am335x_evm_defconfig
$ make

Подготовка к кросс-компиляции под нужную целевую платформу. Необходимо настроить переменные окружения: PATH должна содержать путь до используемого тулчейна компиляции, CROSS_COMPILE и ARCH должны содержать название имена, описывающие используемую архитектуру процессора.

PATH=${HOME}/x-tools/arm-unknown-linux-gnueabi/bin/:$PATH
export CROSS_COMPILE=arm-unknown-linux-gnueabi-
export ARCH=arm

Компиляция выполняется переходом в каталог проекта (папка u-boot) и запуском команды make, где в её командной строке указывается файл конфигурации, например так:

$ cd u-boot
$ make TQM823L_defconfig

При завершении успешной компиляции в основном каталоге проекта появится файл u-boot.bin, это двоичный исполняемый код, предназначенный для работы непосредственно в устройстве (он загружается или прошивается в адресное пространство, откуда начинается выполнение кода при сбросе или включении питания устройства).

В частности, также могут использоваться и другие результаты компиляции:

u-boot - исполняемый файл в ELF-формате, используемый для отладчиков.
u-boot.img - код наподобие u-boot.bin, но с добавленным заголовком.
u-boot.srec - исполняемый код в формате Motorola S-Record, используемый для последовательных соединений.
MLO - Secondary Program Loader (собирается только при необходимости).

Кроме целевых процессоров, U-Boot можно скомпилировать для целей демонстрации:

• Песочница U-Boot (sandox_defconfig), позволяет запустить U-Boot как приложение userspace.
• Симулятор QEMU (qemu_defconfig), позволяет запустить U-Boot в QEMU как "BIOS".

$ qemu-system-arm -M virt -bios u-boot.bin

[Практические лабораторные работы]

Примеры работы с PocketBeagle и Techlab:

https://beagleboard.org/pocket
https://beagleboard.org/techlab

Компиляция и запуск U-Boot в "песочнице", т. е. на машине хоста:

$ git clone git://git.denx.de/u-boot.git
$ cd u-boot
$ chmod -R +x ./scripts/*.sh
$ make sandbox_defconfig
$ make -j $(nproc)
$ ./u-boot

1. Ошибка доступа к скриптам в каталоге scripts:

$ make sandbox_defconfig
  HOSTCC  scripts/basic/fixdep
  HOSTCC  scripts/kconfig/conf.o
  YACC    scripts/kconfig/zconf.tab.c
  LEX     scripts/kconfig/zconf.lex.c
  HOSTCC  scripts/kconfig/zconf.tab.o
  HOSTLD  scripts/kconfig/conf
sh: 1: ./scripts/gcc-version.sh: Permission denied
sh: 1: ./scripts/gcc-version.sh: Permission denied
Kconfig:66: syntax error
Kconfig:65: invalid option
sh: 1: ./scripts/clang-version.sh: Permission denied
Kconfig:74: syntax error
Kconfig:73: invalid option
make[1]: *** [scripts/kconfig/Makefile:97: sandbox_defconfig] Error 1
make: *** [Makefile:586: sandbox_defconfig] Error 2

Эта ошибка возникла из-за того, что исходный код был распакован из ZIP-архива, где не были сохранены атрибуты файлов.

Как исправить:

$ chmod -R +x ./scripts/*.sh

2. Ошибка компиляции:

...
tools/mkeficapsule.c:20:10: fatal error: gnutls/gnutls.h: No such file or directory
   20 | #include < gnutls/gnutls.h>
      |          ^~~~~~~~~~~~~~~~~

.. связана с отсутствием установленной библиотеки gnutls. Как исправить:

Сначала надо узнать имя библиотеки:

$ sudo apt list | grep libgnutls

Из выведенного списка очевидно, что кандидат на имя библиотеки libgnutls28-dev. После этого её надо установить:

$ sudo apt-get install libgnutls28-dev

3. Ошибки компиляции:

cmd/printf.c:403:9: error: ‘errno’ undeclared (first use in this function)
  403 |         errno = 0;
      |         ^~~~~
cmd/printf.c:93:1: note: ‘errno’ is defined in header ‘< errno.h>’; did you
 forget to ‘#include < errno.h>’?
include/ctype.h:1:1: error: expected identifier or ‘(’ before numeric constant
    1 | linux/ctype.h
...
include/ctype.h:1:1: error: expected identifier or ‘(’ before numeric constant
    1 | linux/ctype.h
      | ^~~~~

.. устраняются правкой заголовка include/ctype.h. По непонятной причине в нем было пропущено ключевое слово #include. Т. е. надо строчку "linux/ctype.h" исправить на:

#include < linux/ctype.h>

4. Ошибка отсутствия утилиты cert-to-efi-sig-list:

  CAPSULE_ESL_GEN test/overlay/capsule_esl_file
/bin/sh: 1: cert-to-efi-sig-list: not found
make[1]: *** [scripts/Makefile.lib:392: test/overlay/capsule_esl_file] Error 127
make: *** [Makefile:1915: test/overlay] Error 2

.. решается установкой efitools:

$ sudo apt install efitools

5. Ошибка binman:

/bin/sh: 1: ./tools/binman/binman: Permission denied
make: *** [Makefile:1135: .binman_stamp] Error 126

.. связана с ошибкой символической ссылки ./tools/binman/binman, которая должна ссылаться на файл ./tools/binman/main.py. Это проще всего исправить, если заново создать символическую ссылку binman:

$ rm ./tools/binman/binman
$ cd ./tools/binman
$ ln -s main.py binman
$ chmod +x binman
$ chmod +s main.py
$ cd ../..

[U-Boot и mkimage]

Утилита mkimage используется для создания образов U-Boot, в которых содержится Linux kernel, корневая файловая система (root file system), firmware, блок описания дерева устройств (device tree blob, DTB) и многое другое. Образы могут быть либо в legacy-формате uImage или zImage (например для ARM), либо в более современном FIT-формате fitImage (например для PowerPC).

Пример генерации uImage (опция -a указывает адрес загрузки, опция -e указывает точку входа):

$ mkimage -A arm -O linux -T kernel -C gzip -a 0x80008000 -e \
0x80008000 -n 'Linux' -d zImage uImage

Пример генерации fitImage:

$ mkimage -f kernel.its kernel.itb

[Загрузка образов]

Загрузка из систем хранения. Следующая команда может использоваться для загрузки файлов из разделов FAT:

# fatload mmc 0:1 83000000 uImage

Здесь в командной строке fatload используются опции:

mmc - указывает интерфейс карт MMC.
0 - обозначает первое устройство.
1 - обозначает первый раздел на устройстве.
83000000 - выбранная область RAM для загрузки (байтовый адрес в HEX-формате).
uImage - файл для загрузки.

Загрузка по сети. Загрузку образа можно выполнить по протоколам TFTP и DHCP. Чтобы произвести загрузку через TFTP, необходимо установить переменные окружения ipaddr для текущего адреса устройства и serverip для адреса сервера, где находится загружаемый файл образа:

# setenv ipaddr 192.168.100.2
# setenv serverip 192.168.100.1
# saveenv

Запуск загрузки через TFTP:

# tftpboot 83000000 uImage

Запись NAND. Загруженный образ может быть запрограммирован в flash-память NAND. Для защиты содержимого памяти от повреждений используется кодировка ECC (Error Correction Coding), изучите документацию на вашу плату.

# nandecc hw
# nand erase 300000 400000
# nand write 83000000 300000 400000

В этом примере 0x400000 байт данных образа, находящихся в RAM по адресу 0x83000000, записываются в память NAND по адресу 0x300000.

Чтение NAND. Подобным образом данные могут быть прочитаны из NAND:

# nand read 83000000 300000 400000

Эта команда вычитывает 0x400000 байт данных из NAND по адресу 0x300000 и помещает их в RAM по адресу 0x83000000.

[Boot Kernel]

Ядро, загруженное в память, может быть запущено командой:

bootm < addr_kernel> < addr_ramdisk> < addr_dtb>

Если не предоставляется initramfs, то за адресом ядра kernel может идти -, и далее идет адрес addr_dtb, указывающий на блок дерева устройств. Пример:

# bootm 83000000 - 84000000

[Автоматизация загрузки]

Чтобы создать скрипты U-Boot:

1. Сохраните все команды U-Boot в текстовый файл.
2. Преобразуйте текстовый файл в образ U-Boot с помощью утилиты mkimage.
3. Загрузите файл с помощью TFTP на целевую машину.
4. Используйте "source" для выполнения скрипта.

Вы можете также создать переменную командой setenv, где содержатся все команды. После этого можно запускать эту переменную как скрипт с помощью команды run.

[Falcon Mode]

Это ускоренная процедура загрузки [9, 10], состоящая из последовательности шагов:

ROM -> SPL -> u-boot.bin -> kernel

Разрешение этой конфигурации требует специальной сборки U-Boot после модификации большого количества параметров, находящихся в нескольких конфигурационных файлах.

[Ссылки]

1. Tutorial: Introduction to the Embedded Boot Loader U-boot - Behan Webster, Converse in Code site:youtube.com.
2. The U-Boot Documentation.
3U-Boot Reference Manual.
4. Команды управления переменными окружения Linux.
5. Squashfs 4.0 Filesystem.
6. Experimental support for SquashFS in U-Boot.
7. Device Tree site:wikipedia.org.
8. Embedded Linux | Introduction To U-Boot | Beginners site:youtube.com.
9. Understanding U-Boot Falcon Mode site:bootlin.com.
10. U-Boot Falcon Mode.

 

Добавить комментарий


Защитный код
Обновить

Top of Page