Привет, Хабр!

Некоторое время назад компания STMicroelectronics выпустила интересные процессоры серии STM32MP1. Когда у меня наконец-то дошли руки до отладочной платы на основе этого процессора, я с некоторым удивлением обнаружил, что для нее отсутствуют какие-либо сборки на основе популярных дистрибутивов (Debian, Arch Linux и др). Оставалось только попробовать самому адаптировать какой-нибудь дистрибутив под данную плату. По результатам этого и появилась данная статья.



Что по характеристикам?


Данная статья была бы не полной без хотя бы краткого обзора характеристик процессоров серии STM32MP1. Существует три семейства процессоров серии STM32MP1: STM32MP151, STM32MP153 и STM32MP157. Их основные характеристики приведены в таблице.



Как видим из таблицы, разница между семействами заключается в том, что STM32MP151 имеет одно ядро Cortex-A7, тогда как STM32MP153 и STM32MP157 имеют два таких ядра, а STM32MP157 еще и дополнительно обладает поддержкой 3D GPU. Но в целом характеристики данных процессоров в 2020 году не производят какого-либо впечатления, они достаточно скромные. Почему же я все-таки обратил на них внимание?

Почему STM32MP1?


Действительно, может возникнуть вполне закономерный вопрос: есть же Raspberry Pi, есть Banana Pi, есть Orange Pi, наконец – зачем нужен еще какой-то STM32MP1? Тем более, что все эти платы обычно обладают заметно большей производительностью, чем объект нашего исследования. Ответ прост – пока вы делаете какие-либо поделки для домашнего использования все так и есть, вам надо брать малинку и это будет правильно. Но если же речь идет о серийно выпускаемой продукции для промышленных применений – вот тут начинает играть решающую роль другие вещи, благодаря которым STM32MP1 оказывается в выигрыше:

  • Диапазон рабочих температур. У STM32MP1 он начинается от минус 40 градусов, тогда как у многих процессоров других одноплатников хорошо если он минус 20.
  • Наличие качественной документации. У STMicroelectronics традиционно с этим все довольно неплохо, тогда как документацию на китайские процессоры часто приходится собирать по обрывкам интернетов.
  • Возможность заказать большую партию у проверенных поставщиков. Тот же DigiKey или Mouser способны без проблем отгрузит любое количество STM32MP1, тогда как китайские процессоры придется покупать на сомнительных площадках типа алиэкспресса.

Конечно, ST32MP1 не единственные на рынке процессоров для промышленных применений. Есть и NXP, и TI. Что касается TI, то у меня был проект достаточно сложного модуля на его основе, и остался осадочек от заметного числа аппаратных особенностей, которые не освещены в документации, но при несоблюдении которых процессор мог полностью выходить из строя, причем не сразу, а со временем и в самый неподходящий момент. Кроме того, это был одноядерный процессор, и с ростом числа возложенных на него задач все чаще возникали проблемы с производительностью. В то же время я имел дело с микроконтроллерами фирмы STMicroelectronics, и они зарекомендовали себя достаточно хорошо, поэтому я и решил попробовать поковырять этот их новый камешек.

Отладочная плата


Для проведения экспериментов я приобрел отладочную плату STM32MP157A-DK1. Это достаточно скромная по оснащению плата: у нее нет LCD дисплея как у STM32MP157C-DK2 или такой богатой периферии как у STM32MP157A-EV1. Однако есть разъем для microSD-карты, консоль USB-UART, несколько USB портов и Ethernet. Для первого старта более чем достаточно. А чтобы разбавить сухое повествование какой-нибудь картинкой, я прилагаю фото этой отладочной платы.



Что есть из готового софта?


У STMicroelectronics обычно все достаточно хорошо с точки зрения железа, но ужасно с точки зрения софта. Все эти модификации Atollic True Studio, CubeMX, CubeIDE, которые с каждым новым релизом глючат все больше и больше, навевают некоторую тоску. Немногим лучше дело обстоит и с поддержкой STM32MP1. STMicroelectronics предлагает только некую сборку OpenSTLinux. Эта сборка представляет собой дистрибутив, построенный с помощью Yocto Project. Безусловно, все это может существовать и в таком виде, но для меня главным минусом было отсутствие доступа к репозитариям известных дистрибутивов. Это значит, что вы не сможете поставить себе на плату какой-либо утилиту из репозиториев популярных дистрибутивов просто выполнив команду по типу apt-get install. Часто это и не требуется для встраиваемых решений, однако возможны ситуации, когда такая возможность точно не будет лишней.

Что будем делать?


Итак, задача ясна – нам надо запустить какой-либо популярный дистрибутив на нашей отладочной плате. Мой выбор пал на Arch Linux. Это не самый простой дистрибутив, однако он неплохо адаптирован под устройства на ARM: есть готовые сборки и официальный сайт, посвященный именно этому.

Первым делом я попробовал решить проблему с наскока – просто подсунул загрузчику готовое ядро из состава дистрибутива Arch Linux, собранное под armv7. Такое иногда срабатывало на других платах, однако тут меня ждало фиаско: не смотря на то, что ядро было собрано под правильную архитектуру, оно не запустилось. Ну что ж, значит, надо собрать свое ядро и заодно уж свой загрузчик. План действий у меня был такой:

  1. Собираем загрузчик U-Boot.
  2. Собираем ядро Linux.
  3. Размечаем microSD-карту.
  4. Записываем на microSD-карту загрузчик, ядро и корневую файловую систему.
  5. Profit

Подготовка к сборке


Для претворения обозначенного плана в жизнь нам понадобится компьютер с Linux и картридером для записи на microSD-карту. Я использовал ноутбук с Debian 10, но вообще это не принципиально, могут только немого отличаться названия утилит. Итак, ставим требуемые утилиты. Отмечу сразу, что сейчас и далее все команды надо выполнять под пользователем root или же через sudo.

apt-get install git
apt-get install make
apt-get install gcc
apt-get install gcc-arm-linux-gnueabihf
apt-get install bison
apt-get install flex
apt-get install g++
apt-get install rsync
apt-get install libncurses-dev

В рамках подготовки к сборке создаем в рабочей директории три директории: u-boot (для загрузчика), buildroot (для сборки системы) и archlinux (для дистрибутива):

mkdir u-boot
mkdir buildroot
mkdir archlinux

Эти директории понадобятся нам дальше. Я буду ссылаться на эти названия дальше по тексту статьи.

Сборка U-Boot


Про U-Boot написано уже достаточно много статей, и в рамках данной я не буду углубляться с пояснениями что это, для чего нужно и как работает. Скажу лишь только, что это загрузчик, обеспечивающий старт Linux на ARM устройствах. Исходный код загрузчика U-Boot доступен на GitHub.

Для того, чтобы собрать U-Boot, первым делом клонируем репозиторий U-Boot в директорию u-boot, созданную нами ранее:

git clone https://github.com/u-boot/u-boot

Для успешной сборки U-Boot нам потребуется файл дерева устройств (device tree) и файл конфигурации U-Boot.

Файл дерева устройств является аппаратно-зависимым файлом. Этот файл описывает конфигурацию процессора под конкретную плату. Если вы делаете свою железку на основе какого-либо процессора ARM и планируете запускать на ней Linux, то вам потребуется разрабатывать свой файл дерева устройств под нее (либо же адаптировать какой-то готовый). Однако на многие отладочные платы существуют уже готовые файлы: заботливые разработчики U-Boot включают их в свой репозиторий. Итак, смотрим директорию u-boot/arch/arm/dts. В ней должен быть файл stm32mp157a-dk1.dtb – это и есть файл дерева устройств под нашу отладочную плату.

UPD: Как справедливо заметили в комментариях, файл stm32mp157a-dk1.dtb появится после выполнения первой сборки U-Boot. До запуска процесса сборки в директории u-boot/arch/arm/dts содержится исходный файл stm32mp157a-dk1.dts

В файле конфигурации U-Boot прописываются основные настройки загрузчика.

Конфигурировать с нуля U-Boot – достаточно долгий и трудоемкий процесс, потому что настроек там великое множество. Для этих целей существуют как консольные, так и графические конфигураторы. Однако и тут нам повезло: в директории u-boot/configs имеется файл stm32mp15_basic_defconfig. Это файл базовой конфигурации U-Boot под отладочные платы STM32MP15. Открываем этот файл и видим, что нам для быстрого старта достаточно поменять всего одну строчку: вместо

CONFIG_DEFAULT_DEVICE_TREE=”stm32mp157c-ev1”

пишем

CONFIG_DEFAULT_DEVICE_TREE=”stm32mp157a-dk1”

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

Теперь все готово для сборки U-Boot. Применяем наш конфиг:

make CROSS_COMPILE=arm-linux-gnueabihf- stm32mp15_basic_defconfig

И запускаем сборку:

make CROSS_COMPILE=arm-linux-gnueabihf-

Если все прошло без ошибок, то в директории u-boot у нас должна появиться куча файлов. Из них интерес для нас представляют два: u-boot-spl.stm32 и u-boot.img.

Первый файл – это так называемый первичный загрузчик (First Stage Boot Loader – FSBL). Он находится перед U-Boot, стартует первым и инициализирует DDR3 память, которая необходима для старта U-Boot. В других платах часто FSBL объединен с U-Boot в один образ, однако здесь придется каждый образ записывать на флешку отдельно.

На этом с U-Boot пока все, сохраним обозначенные файлы и перейдем непосредственно к сборке ядра Linux.

Сборка ядра Linux


Для сборки ядра Linux я буду использовать Buildroot. Конечно, для этих целей можно использовать не менее популярный Yocto или же вообще попробовать собрать ядро из исходников с kernel.org. Однако у меня был некоторый опыт работы с Buildroot, поэтому на нем я и остановил свой выбор. Кроме того, с помощью Buildroot также собирается и корневая файловая система (rootfs) и даже загрузчик U-Boot.

Теперь любыми доступными средствами качаем архив с Buildroot с официального сайта, распаковываем в директорию buildroot и переходим в нее.

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

Идем в директорию buildroot/configs и видим, что разработчики уже добавили конфигурационный файл под нашу плату: имеется файл stm32mp157a_dk1_defconfig (верно для сборки Buildroot-2020.05, в более ранних версиях этого файла еще не было).

Я пробовал собирать ядро 5.4.26 с использованием этого конфигурационного файла, и оно в целом успешно стартовало на моей плате. Однако по какой-то причине файл дерева устройств для Linux в данной сборке оказался урезанным: по умолчанию не было даже поддержки USB портов. Будем надеяться, что со временем этот баг починят, но что делать сейчас?

Я пошел гуглить данную проблему и наткнулся на репозитории фирмы STMicroelectronics, где и нашел исходники Linux 4.19 с патчами для их продуктов. В том числе, там же оказались и правильные файлы DTB. Осталось только указать Buildroot использовать данный репозиторий при сборке ядра. Для этого копируем файл stm32mp157a_dk1_defconfig и переименовываем его в stm32mp157a_dk1_new_defconfig. Открываем его и вносим следующие изменения:

Вместо

BR2_PACKAGE_HOST_LINUX_HEADERS_CUSTOM_5_4=y

Пишем

BR2_PACKAGE_HOST_LINUX_HEADERS_CUSTOM_4_19=y

Вместо

BR2_LINUX_KERNEL_CUSTOM_VERSION=y
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="5.4.26"

Пишем

BR2_LINUX_KERNEL_CUSTOM_TARBALL=y
BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,STMicroelectronics,linux,v4.19-stm32mp-r1.2)/linux-v4.19-stm32mp-r1.2.tar.gz"

Сохраняем и закрываем файл. Конфигурационный файл готов, давайте применим его (выполнять надо из директории buildroot):

make CROSS_COMPILE=arm-linux-gnueabihf- stm32mp157a_dk1_new_defconfig

Эта команда перенесет информацию из нашего конфигурационного файла stm32mp157a_dk1_defconfig в файл .config, который находится в директории buildroot. В дальнейшем именно на основе файла .config будет строиться сборка.

Итак, теперь все почти что готово для начала процесса сборки, однако перед этим необходимо сконфигурировать наше ядро.

Здесь стоит сказать, что по умолчанию в ядро будет включен минимальный функционал. Если мы хотим его расширить, то ядро необходимо будет конфигурировать под себя. Как минимум надо будет добавить в ядро поддержку Control Group: без этого наш Arch Linux не запустится. Дополнительно в качестве примера я продемонстрирую, как добавить в ядро поддержку работы USB-flash накопителей: в результате наша отладочная плата сможем работать с флешками.
Для запуска конфигуратора ядра из директории buildroot выполняем команду

make linux-menuconfig

и идем пить чай. Данный процесс не быстрый и в зависимости от мощности вашего компьютера может занять от пятнадцати минут до нескольких часов. Важно: в процессе работы buildroot необходимо стабильное соединение с интернетом, будет скачано много разных пакетов.
Если в процессе выскочит ошибка вида

configure: error: you should not run configure as root (set FORCE_UNSAFE_CONFIGURE=1 in environment to bypass this check)
See `config.log' for more details

необходимы будет выполнить команду

export FORCE_UNSAFE_CONFIGURE=1

и повторно запустить конфигуратор ядра.

По итогу должно появиться окно конфигуратора:



Добавляем поддержку Control Group: General setup -> Control Group support и выставляем звездочку с помощью пробела:



А как добавить поддержку флешек?
Добавляем поддержку SCSI устройств. Это древнее наследие из 80-х годов, без которого, однако, не заведется работа с USB FLASH накопителями. Идем в Device Drivers -> SCSI support и выставляем звездочки в соответствии с рисунком:



Добавляем поддержку непосредственно работы с USB FLASH накопителями. Идем в Device Drivers -> USB support и ставим звездочку USB Mass Storage support:



Теперь, чтобы получилось корректно примонтировать FLASH накопитель добавляем дополнительно следующие атрибуты: File systems -> Native language support -> Codepage 437 и File systems -> Native language support -> NLS ISO 8859-1:





Этого хватило для того, чтобы USB FLASH накопители успешно определялись системой и монтировались.

После того, как все настройки в конфигураторе ядра сделаны, сохраняем их кнопкой Save и выходим из конфигуратора кнопкой Exit.

Теперь осталось только запустить процесс сборки командой:

make CROSS_COMPILE=arm-linux-gnueabihf-

и можно второй раз пойти пить чай, этот процесс тоже занимает немало времени.

Если все прошло без ошибок, то в директории buildroot/output/images должен появиться следующий набор файлов:

  • rootfs.ext2 – собранная корневая файловая система с ext2. Для нас не представляет интереса;
  • rootfs.ext4 – собранная корневая файловая система с ext4. Пригодится нам чуть позже;
  • sdcard.img – Образ microSD-карты, включающий в себя FSBL+U-Boot+zImage+rootfs. Файлик для ленивых, позволяет не утруждать себя разметкой microSD-карты и сразу залить на нее всю систему. Конечно же, это не наш путь :).
  • stm32mp157a-dk1.dtb – файл дерева устройства. Обязательно нам пригодится для запуска системы;
  • u-boot.img и u-boot-spl.stm32 – файл FSBL и U-Boot. Поскольку мы собирали их на прошлом шаге, они нам не нужны;
    А зачем мы собирали их отдельно?
    Действительно, Buildroot позволяет собрать вместе с ядром и корневой файловой системой еще и загрузчик U-Boot. Это удобно на этапе, когда уже пройдены все трудности первоначального старта. Но в самом начале пути обычно быстрее и удобнее собрать и запустить на плате только один U-Boot, и когда он уже гарантированно стабильно работает – переходить к запуску ядра Linux.
  • zImage – сердце всей системы – файл сжатого ядра Linux.

Итак, процесс сборки завершен, теперь приступаем к разметке microSD-карты памяти и созданию разделов на ней.

Разметка и разделы microSD-карты


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

Сразу отмечу, что microSD-карта, с которой запускается система на STM32MP1, должна иметь GPT-разметку. В этом нам поможет утилита gdisk, но об этом чуть позже.

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



Как видно из рисунка, карта должна содержать минимум 5 разделов: fsbl1, fsbl2, ssbl, kernel, rootfs. Дополнительно можно также создать один или несколько разделов data для хранения на них какой-либо информации.

Разделы fsbl1 и fsbl2 являются полностью идентичными и на них записывается первичный загрузчик (как вы помните, это файл u-boot-spl.stm32, полученный нами в процессе сборки U-Boot). Не смотря на то, что работать все должно и только с одним таким разделом, документация на STM2MP1 рекомендует делать их два. К этим разделам предъявляются и другие требования:

  • Размер каждого раздела должен быть 256 КБ.
  • Каждый раздел должен иметь имя, включающее в себя кодовое слово fsbl (fsbl1 и fsbl2). Это очень важно: если разделу не присвоить имя в соответствии с этим правилом, то система вообще не запускается.

Раздел ssbl предназначен для записи загрузчика U-Boot (файл u-boot.img, полученный нами в процессе сборки U-Boot). Рекомендуемый размер раздела ssbl 2 МБ.
Раздел kernel предназначен для записи на него ядра Linux (файл zImage), дерева устройств (файл stm32mp157a-dk1.dtb), а также скрипта для U-Boot, с помощью которого будет произведен запуск системы. Рекомендуемый размер раздела kernel 64 МБ.

Раздел rootfs предназначен для записи корневой файловой системы. Мы попробуем записать на него корневую файловую систему, собранную Buildroot, а также корневую файловую систему Arch Linux. Рекомендуемый размер раздела rootfs – 1 ГБ или более.
Раздел data предназначен для хранения пользовательских данных. Можно сделать один такой раздел или несколько. А можно вообще обойтись без него. В рамках данной статьи я не буду создавать этот раздел.

Итак, приступаем к разметке. Вставляем microSD-карту в картридер нашего компьютера с Linux на борту и любыми доступными способами (например, с помощью dmesg) определяем имя появившегося устройства. В моем случае это /dev/sdb. В вашем случае это может быть другое имя.

Запускаем утилиту gdisk и полностью удаляем имеющуюся на microSD-карте разметку:

root@debian:/home/myuser# gdisk /dev/sdb
GPT fdisk (gdisk) version 1.0.3
Partition table scan:
  MBR: protective
  BSD: not present
  APM: not present
  GPT: present
Found valid GPT with protective MBR; using GPT.
Command (? for help): x
Expert command (? for help): z
About to wipe out GPT on /dev/sdb. Proceed? (Y/N): y
GPT data structures destroyed! You may now partition the disk using fdisk or
other utilities.
Blank out MBR? (Y/N): y

На всякий случай забиваем начало microSD-карточки нулями.

dd if=/dev/zero of=/dev/sdb bs=1M count=64

Теперь снова запускаем gdisk, добавляем разметку и создаем 5 разделов на microSD-карте согласно таблице, которую я приводил выше:

root@debian:/home/myuser# gdisk /dev/sdb
GPT fdisk (gdisk) version 1.0.3

Partition table scan:
  MBR: not present
  BSD: not present
  APM: not present
  GPT: not present

Creating new GPT entries.

Command (? for help): o
This option deletes all partitions and creates a new protective MBR.
Proceed? (Y/N): y

Command (? for help): n
Partition number (1-128, default 1): 1
First sector (34-30873566, default = 2048) or {+-}size{KMGTP}: 
Last sector (2048-30873566, default = 30873566) or {+-}size{KMGTP}: +256K
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): 
Changed type of partition to 'Linux filesystem'

Command (? for help): n
Partition number (2-128, default 2): 2
First sector (34-30873566, default = 4096) or {+-}size{KMGTP}: 
Last sector (4096-30873566, default = 30873566) or {+-}size{KMGTP}: +256K
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): 
Changed type of partition to 'Linux filesystem'

Command (? for help): n
Partition number (3-128, default 3): 3
First sector (34-30873566, default = 6144) or {+-}size{KMGTP}: 
Last sector (6144-30873566, default = 30873566) or {+-}size{KMGTP}: +2M
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): 
Changed type of partition to 'Linux filesystem'

Command (? for help): n
Partition number (4-128, default 4): 4
First sector (34-30873566, default = 10240) or {+-}size{KMGTP}: 
Last sector (10240-30873566, default = 30873566) or {+-}size{KMGTP}: +64M
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): 
Changed type of partition to 'Linux filesystem'

Command (? for help): n
Partition number (5-128, default 5): 5
First sector (34-30873566, default = 141312) or {+-}size{KMGTP}: 
Last sector (141312-30873566, default = 30873566) or {+-}size{KMGTP}: 
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): 
Changed type of partition to 'Linux filesystem'

Command (? for help): w

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!

Do you want to proceed? (Y/N): y
OK; writing new GUID partition table (GPT) to /dev/sdb.
The operation has completed successfully.

Далее добавляем имена разделам на microSD-карте. Как вы помните, это особенно критично для первых разделов, куда будет записан FSBL: если не присвоить им требуемые имена, то система не запустится:

root@debian:/home/myuser# gdisk /dev/sdb
GPT fdisk (gdisk) version 1.0.3

Partition table scan:
  MBR: protective
  BSD: not present
  APM: not present
  GPT: present

Found valid GPT with protective MBR; using GPT.

Command (? for help): c
Partition number (1-5): 1
Enter name: fsbl1

Command (? for help): c
Partition number (1-5): 2
Enter name: fsbl2

Command (? for help): c
Partition number (1-5): 3
Enter name: ssbl

Command (? for help): c
Partition number (1-5): 4
Enter name: kernel

Command (? for help): c
Partition number (1-5): 5
Enter name: roootfs

Command (? for help): w

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!

Do you want to proceed? (Y/N): y
OK; writing new GUID partition table (GPT) to /dev/sdb.
The operation has completed successfully.

В завершении работы с microSD-картой нам надо добавить атрибут legacy BIOS bootable в раздел, на котором у нас будет записано ядро Linux. Без этого атрибута ядро запускаться отказывалось:

root@debian:/home/myuser# gdisk /dev/sdb
GPT fdisk (gdisk) version 1.0.3

Partition table scan:
  MBR: protective
  BSD: not present
  APM: not present
  GPT: present

Found valid GPT with protective MBR; using GPT.

Command (? for help): x

Expert command (? for help): a
Partition number (1-5): 4
Known attributes are:
0: system partition
1: hide from EFI
2: legacy BIOS bootable
60: read-only
62: hidden
63: do not automount

Attribute value is 0000000000000000. Set fields are:
  No fields set

Toggle which attribute field (0-63, 64 or <Enter> to exit): 2
Have enabled the 'legacy BIOS bootable' attribute.
Attribute value is 0000000000000004. Set fields are:
2 (legacy BIOS bootable)

Toggle which attribute field (0-63, 64 or <Enter> to exit): 

Expert command (? for help): w

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!

Do you want to proceed? (Y/N): y
OK; writing new GUID partition table (GPT) to /dev/sdb.
The operation has completed successfully.

Вот и все, разметка карты памяти готова. На всякий случай проверим, что все записалось как надо. Для этого опять запустим gdisk и выполним команду p. Результат должен советовать рисунку:



Теперь создаем файловую систему ext4 на /dev/sdb4 и /dev/sdb5:

mkfs.ext4 /dev/sdb4
mkfs.ext4 /dev/sdb5

И прописываем метки тома, чтобы потом было проще к ним обращаться:

e2label /dev/sdb4 kernel
e2label /dev/sdb5 rootfs

На этом создание разделов карточки памяти закончено, можно переходить к записи на нее файлов.

Запись на microSD-карту


Итак, на текущем этапе все готово для записи на microSD-карту. Вставляем ее в картриред компьютера с Linux и записываем первичный загрузчик (FSBL) в первый и второй разделы mocroSD-карты:

dd if=u-boot/u-boot-spl.stm32 of=/dev/sdb1
dd if=u-boot/u-boot-spl.stm32 of=/dev/sdb2

Теперь запишем U-Boot на третий раздел microSD-карты:

dd if=u-boot/u-boot.img of=/dev/sdb3

Дальше надо скопировать ядро, файл дерева устройств и скрипт загрузки в четвертый раздел на microSD-карте.

Прежде чем приступить к копированию файлов необходимо небольшое пояснения про скрипт загрузки. В этом скрипте, собственно, указывается различная информация для U-Boot, с помощью которой он сможет загрузить систему и передать управление ядру. Существуют разные способы написания этих скриптов, однако самый простой (на мой взгляд) описан в документации на STM32MP1: необходимо в корне раздела kernel создать директорию /extlinux и в ней создать текстовый файл с именем extlinux.conf со следующим содержимым:

LABEL stm32mp157a-dk1
KERNEL /zImage
FDT /stm32mp157a-dk1.dtb
APPEND root=/dev/mmcblk0p5 rootwait rw console=ttySTM0,115200

Здесь все достаточно просто: мы указываем загрузчику где брать ядро, дерево устройств, корневую файловую систему и говорим, что рабочей консолью у нас будет порт ttySTM0.

Теперь копируем ядро:

cp -a buildroot/output/images/zImage /media/myuser/kernel/

Примечание: в директорию /media/myuser/ у меня происходит монтирование microSD-карточки при установке в картиридер. В вашем случае это может быть другая директория.

Копируем файл дерева устройств:

cp -a buildroot/output/images/stm32mp157a-dk1.dtb /media/myuser/kernel/

Создаем директорию:

mkdir /media/myuser/kernel/extlinux

Создаем файл:

nano /media/myuser/kernel/extlinux/extlinux.conf

и наполняем его содержимым:

LABEL stm32mp157a-dk1
KERNEL /zImage
FDT /stm32mp157a-dk1.dtb
APPEND root=/dev/mmcblk0p5 rootwait rw console=ttySTM0,115200

Сохраняем файл и закрываем редактор.

На этом четвертый раздел microSD-карты готов: ядро linux и все вспомогательные файлы для него уже записаны. Уже на этом этапе если вставить microSD-карту в отладочную плату должно загружаться ядро Linux, правда, в конечном итоге оно вылетит в kernel panic по причине того, что не удается смонтировать корневую файловую систему. Это и не удивительно, ведь мы пока что ее на записали.

Остался финальный этап, на котором мы запишем на microSD-карту корневую файловую систему. И вот здесь возможны различные варианты:

  1. Запишем корневую файловую систему, сгенерированную Buildroot
  2. Запишем корневую файловую систему Arch Linux

Сначала запишем корневую файловую систему, которую нам сгенерировал Buildroot и попробуем запустится с ней. Это не являлось целью данной статьи, однако мне показалось, что в целом это может оказаться полезным для каких-либо применений, тем более, что данное действо не займет много времени. Корневая файловая система записывается в пятый раздел нашей microSD-карты всего одной командой:

dd if=buildroot/output/images/rootfs.ext4 of=/dev/sdb5

Теперь вставим карточку памяти в отладочную плату и запустим систему. Наблюдать вывод отладочной информации мы будем через консоль USB-UART: доступ к ней обеспечивается посредством microUSB порта на плате STM32MP157A-DK1. Отображение выводимой информации возможно в любой терминальной программе, например Putty или Minicom. В рамках данной статьи я использовал последнюю, открыв еще одно окошко терминала в Debian.

Теперь вставляем microSD-карточку в отладочную плату, подаем на плату питание и смотрим в терминал. Если все было сделано правильно, то туда должны высыпаться логи FSBL, U-Boot, kernel и в конечном счете – появиться приглашение ввести логин. Вводим root и – вуаля – мы попадаем в консоль системы, которую только что собрали:



Да, в ней нет даже менеджера пакетов и вообще функционал очень скудный, но с помощью Buildroot можно очень здорово его нарастить и создать реально работающую сложную систему. Пока же ее размер составляет всего 7 мегабайт!



Убедившись, что самодельная корневая файловая система успешно запускается, пришло время запустить Arch Linux. Опять вставляем microSD-карту в картридер нашего компьютера и форматируем еще раз пятый раздел карты памяти:

mkfs.ext4 /dev/sdb5

Качаем архив с Arch Linux, собранным под armv7, с официального сайта. Распаковываем архив в директорию archlinux и с помощью команды:

cp -a archlinux/* /media/myuser/rootfs 

Копируем его в раздел rootfs microSD-карты.

Чистим директорию /media/myuser/rootfs/boot: содержимое нам не нужно, потому что ядро и дерево устройств у нас находятся в отдельном разделе microSD-карты:

rm –rf /media/myuser/rootfs/boot/*

Позже в директорию boot можно будет примонтировать раздел /dev/sdb4, где у нас хранится образ ядра.

После этого вставляем microSD-карту в отладочную плату, подаем питание и радуемся работающему ArchLinux:



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



Заключение


В ходе данной статьи мы вдоволь наигрались с отладочной платой STM32MP157A-DK1: собрали под нее U-Boot, ядро Linux, собственную корневую файловую систему, а также запустили Arch Linux и Debian. Надеюсь, данный материал окажется кому-то полезным как при работе с процессорами семейства STM32MP1, так и с любыми другими одноплатниками на ARM.