Pull to refresh

Обновление Linux в устройстве на базе чипа Altera SoC FPGA и получение доступа к расшаренным ресурсам Windows-сервера

Reading time 8 min
Views 26K


Недавно компания Terasic начала продажи весьма интересной платы DE0-Nano-SoC Kit. Интересна она тем, что за весьма скромную цену предлагается очень мощный и функционально-насыщенный комплект разработчика на основе чипа Altera Cyclone V SoC FPGA со встроенным двухъядерным процессором ARM Cortex-A9. Кроме того, производитель в комплекте с платой даёт ОС Linux, развёрнутую на карту памяти MicroSD.

Но получив эту плату в своё распоряжение, я довольно быстро наткнулся на несколько проблем, обусловленых тем, что Linux был скомпилирован из исходников Yocto Project. В основном все проблемы были связаны с отсутствием общедоступных репозиториев, из которых можно было бы добавить в систему недостающие компоненты. Например, для того, чтобы получить доступ с этого устройства через сеть к расшаренным ресурсам Windows-сервера, в ядре не хватало модуля поддержки файловой системы Cifs.

Поэтому прежде всего было решено обновить ядро, заменить Yocto на более привычный Debian Wheezy и доустановить всё, что необходимо для доступа к расшаренным ресурсам Windows-сервера.

Процесс сборки изучался мной и выполнялся следуя рекомендациям из этой статьи, за что её автору Des333 огромное спасибо!

Полная переделка в мои планы не входила, поэтому загрузчики на карточке было решено оставить родные — от образа Linux 3.13, идущего в комплекте с платой. Так что раздел с типом A2 было решено не трогать совсем.

Задачи


  • Обновить ядро Linux
  • Заменить RootFS на Debian 7
  • Доточить образ так, чтобы его можно было апдейтить из Интернета
  • Примонтировать директорию, расшаренную на сервере Windows

Сборка ядра


Так как основной моей рабочей средой по жизни является Windows, то все действия по сборке Linux выполнялись из-под ОС Linux Mint 17.2 Cinnamon, установленной на виртуальную машину.

1. Запускаем терминалку и входим в root-режим — чтобы не набирать каждый раз команду sudo:
sudo -i

При этом /root будет нашей домашней директорией — всё будем делать в ней.

2. Компилировать ядро будем с помощью кросс-компилятора, входящего в пакет Altera SoC Embedded Design Suite (EDS). Поэтому скачиваем и устанавливаем самый свежий пакет Altera SoC EDS. На данный момент времени Altera SoC EDS имеет версию 15.0. Скачать этот пакет можно прямо с сайта Альтеры.

Altera SoC EDS установится в директорию /root/altera/15.0.

3. Устанавливаем build-essential:
apt-get install build-essential

4. Установливаем libncurses:
apt-get install libncurses5-dev

5. Скачиваем исходники linux-socfpga из репозиториев Альтеры и распаковываем их в домашнюю директорию:

  • Заходим в релизы linux-socfpga в репозиториях Альтеры
  • Находим нужный релиз. Я выбрал версию 4.1 — так как это была самая свежая стабильная версия на данный момент времени
  • Скачиваем архив с исходниками
  • Распаковываем исходники в домашнюю директорию

В результате появляется директория /root/linux-socfpga-4.1 с исходниками ядра Linux версии 4.1.

Поправка (11.02.2016):
Нужно брать не master и не tags а бренчи socfpga-*.
Например, socfpga-4.3
Именно туда накладывают патчи с нужной для SoC функциональностью.
Поэтому за исходниками нужно заходить сюда. Большое спасибо Des333 за подсказку!

6. Запускаем альтеровский скрипт, который запустит новый BASH и подправит в нём некоторые переменные окружения (например, PATH). Все действия по компиляции будем проводить не выходя из этого BASH:
cd /root/altera/15.0/embedded
./embedded_command_shell.sh

7. Создаём несколько переменных окружения:
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
export LOADADDR=0x8000

8. Создаём дефолтную конфигурацию для socfpga:
cd /root/linux-socfpga-4.1
make socfpga_defconfig

При этом будет создан конфигурационный файл .config, заточенный для компиляции под ARM.

9. Добавляем недостающие компоненты в конфигурацию ядра (или удаляем лишние):
make menuconfig

При этом откроется псевдографическое окно с менюшками.



Нам нужно добавить драйвер файловой системы CIFS — чтобы иметь возможность заходить на сетевые расшаренные ресурсы. Существует два способа добавления драйверов в систему — добавить прямо в ядро или добавить в виде внешних подключаемых модулей.

Итак, идём по пути File Systems -> Network File Systems, становимся на CIFS Support и нажимаем клавишу пробел — напротив строки CIFS Suport должна появиться буква M — значит будет использоваться подключаемый внешний модуль. Нужно будет позднее скомпилировать его отдельно и положить в директорию внешних модулей. Если же нажать клавишу пробел ещё раз, то буква M изменится на символ звёздочки — значит драйвер будет встроен прямо в ядро.

Примечание: в дальнейшем, при проверке работоспособности системы, выяснилось, что внешний модуль cifs крэшится при попытке копирования файла с расшаренного диска сервера Windows. Встроенный же в ядро драйвер cifs работал совершенно нормально. Хотя при использовании внешних модулей с другими версиями ядра (например, 3.19) подобных проблем не возникало. Причину происходящего мне так и не удалось выяснить.

Также нужно включить поддержку HighMem — иначе система не сможет использовать верхние 256 мегабайт ОЗУ. Для этого идём по пути Kernel Features -> High Memory Support и также нажимаем клавишу пробел.

Выходим из меню — нажимаем EXIT пока не выйдем. На вопрос — надо ли сохранять конфигурацию — отвечаем Yes.

10. Компилируем ядро:
make uImage

В моём случае виртуальной машине было отдано только одно ядро. Процесс компиляции занял около 20 минут. Если же компилирование будет выполняться в машине с несколькими ядрами, то для скорости можно распараллелить процесс компиляции на несколько ядер. Для этого надо явно задать количество ядер через опцию -j. Например, для компиляции силами трёх ядер:
make -j 3 uImage

11. Компилируем dtb-файл, соответствующий нашему устройству. Если воспользоваться старым dtb-файлом, то или устройство повиснет при загрузке или будут страшные глюки при работе:

  • Ищем все файлы, имеющие в названии cyclone5 и заканчивающиеся на dts:
    find ~/linux-socfpga-4.1 -name "*cyclone5*dts"
    

  • Выбираем наиболее подходящий из найденых файлов. Я просто просматривал их содержимое и в одном из них увидел слово terasic. Мне подумалось, что это самый подходящий файл для данного устройства — вот его и использовал. Файл назывался socfpga_cyclone5_sockit.dts.
  • Запускаем компиляцию socfpga_cyclone5_sockit.dtb:
    make socfpga_cyclone5_sockit.dtb
    


В результате компиляции создалось два файла:
/root/linux-socfpga-4.1/arch/arm/boot/zImage
/root/linux-socfpga-4.1/arch/arm/boot/dts/socfpga_cyclone5_sockit.dtb

12. Если на этапе конфигурации был выбран вариант использования внешних модулей, то необходимо скомпилировать их.
Компилируем модуль CIFS:
make M=fs/cifs

и компилируем модули криптографии — они понадобятся при монтировании расшаренных ресурсов Windows:
make M=crypto

13. Копируем файлы ядра и dtb на карточку. Исходно карточка была нарезана так, что ядро и DTB-файл лежали на отдельном партишене FAT32. Вот на него эти файлы и записываем. Единственное замечание: DTB-файл нужно переименовать — чтобы он назывался также, как тот, который уже лежит на разделе FAT32 карточки:

  • Подключаем карточку к виртуальной машине. Мне пришлось воспользоваться внешним кардридером, подключенным прямо к порту USB2 компьютера. Сделать то-же самое через встроенный в компьютер кардридер почему-то не удалось. Также не удалось подсоединить внешний кардридер к виртуальной машине, если подключать его через порт USB3.
  • Произойдёт автомонтирование разделов карточки — нельзя размонтировать разделы через GUI, потому что в этом случае происходит полное отключение кардридера от виртуальной машины.
  • Смотрим названия примонтированных разделов:
    mount
    

    Увидим нечто в этом роде:
    /dev/sdb1 on /media/user/F725-1429 type vfat (rw,nosuid,nodev,uid=1000,gid=1000,shortname=mixed,dmask=0077,utf8=1,showexec,flush,uhelper=udisks2)
    /dev/sdb2 on /media/user/41cad05c-898e-49a3-9d00-02b92fa817ba type ext3 (rw,nosuid,nodev,uhelper=udisks2)
    

    Раздел типа vfat (первая строка) — то, что нас интересует в данный момент.
  • Смотрим, что лежит на разделе vfat:
    ll /media/user/F725-1429
    

    Видим нечто в этом роде:
    -rw-r--r--  1 user user 1164128 Apr 20 20:23 de0_nano_soc.rbf
    -rw-r--r--  1 user user   15274 Jul 26 17:08 socfpga.dtb
    -rw-r--r--  1 user user     176 Apr 20 19:59 u-boot.scr
    -rw-r--r--  1 user user 3371472 Jul 29 16:50 zImage
    

    Значит dtb-файл называется socfpga.dtb.
  • Копируем наши файлы на карточку:
    cp /root/linux-socfpga-4.1/arch/arm/boot/zImage /media/user/F725-1429/
    cp /root/linux-socfpga-4.1/arch/arm/boot/dts/socfpga_cyclone5_sockit.dtb /media/user/F725-1429/socfpga.dtb
    


Сборка файловой системы


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

Собирать будем Debian 7 Wheezy:

1. Устанавливаем пакеты, которые понадобятся для сборки файловой системы:
apt-get install debootstrap qemu-user-static binfmt-support

2. Создаем директорию и загружаем в неё все необходимые файлы:
cd /root
mkdir debian7
debootstrap --arch armel --foreign wheezy debian7 http://ftp.debian.org/debian

3. Чтобы запускать приложения, собранные под ARM-архитектуру, будем использовать qemu static. Для этого скопируем файл в нашу директорию debian7:
cp /usr/bin/qemu-arm-static debian7/usr/bin/

4. Переходим в нашу новую файловую систему:
chroot debian7 /bin/bash

5. Если приглашение интерпретатора изменилось на «I have no name!@hostname:/#», значит всё прошло успешно.
Заканчиваем процесс сборки:
/debootstrap/debootstrap --second-stage

6. В /etc/inittab оставляем следующие строки:
/etc/inittab
id:5:initdefault:
si::sysinit:/etc/init.d/rcS
~~:S:wait:/sbin/sulogin
l0:0:wait:/etc/init.d/rc 0
l1:1:wait:/etc/init.d/rc 1
l2:2:wait:/etc/init.d/rc 2
l3:3:wait:/etc/init.d/rc 3
l4:4:wait:/etc/init.d/rc 4
l5:5:wait:/etc/init.d/rc 5
l6:6:wait:/etc/init.d/rc 6
z6:6:respawn:/sbin/sulogin
S:2345:respawn:/sbin/getty 115200 console

7. Устанавливаем пароль для root-аккаунта:
passwd

8. Запаковываем новую файловую систему в архив:
tar -cpzf debian7.tar.gz --exclude=debian7.tar.gz  /

9. Выходим из chroot:
exit

10. Размонтируем и затем форматируем раздел ext3 на карточке (названия разделов смотрим в пункте 13 из сборки ядра):
umount /dev/sdb2
mkfs.ext3 /dev/sdb2

11. Монтируем раздел ext3:
mount /dev/sdb2 /mnt/

12. Распаковываем архив с файловой системой на карточку в раздел ext3:
tar -xzf /root/debian7/debian7.tar.gz -C /mnt/

13. Если при сборке ядра был выбран вариант использования внешних модулей, то необходимо записать на карточку внешние модули, скомпилированные на этапе 12 процесса сборки ядра:
cd /mnt/lib
mkdir modules
mkdir modules/4.1.0
mkdir modules/4.1.0/extra
mkdir modules/4.1.0/kernel
mkdir modules/4.1.0/kernel/crypto
cp /root/linux-socfpga-4.1/fs/cifs/cifs.ko ./modules/4.1.0/extra/
cp /root/linux-socfpga-4.1/crypto/*.ko ./modules/4.1.0/kernel/crypto/

14. Размонтируем разделы:
umount /dev/sdb1
umount /dev/sdb2

На этом всё — карточка готова, можно устанавливать её в устройство и загружаться.

Окончательная доводка


После загрузки устройства дотачиваем образ на месте:

1. Логинимся в Debian на устройстве, подключившись к нему через встроенный serial-порт.

2. Если при сборке ядра был выбран вариант использования внешних модулей, то необходимо сгенерить файлы с информацией о внешних модулях ядра:
depmod -a

3. Добавляем в список репозиториев репозиторий Debian 7 (я добавил немецкий сервер):
echo "deb http://ftp.de.debian.org/debian wheezy main" > /etc/apt/sources.list

4. Подключаем устройство к Ethernet-сети. Получаем адрес по DHCP:
dhclient -4 eth0

5. Поднимаем NTP, так как с неправильным временем не удастся примонтировать расшаренные ресурсы:
apt-get update
apt-get install ntp

6. Устанавливаем наш часовой пояс:
dpkg-reconfigure tzdata

7. Для проверки, что всё собралось нормально, монтируем серверную шару. Например, в моём случае я делал это так:
mount //192.168.48.4/distrib /mnt -o username=jok40

8. Устанавливаем SSH-сервер. Пользоваться serial-портом неудобно, так как при работе через него происходит заворот набираемых команд на начало строки после достижения колонки 80:
apt-get install openssh

9. Назначаем статический адрес интерфейсу eth0 — чтобы в дальнейшем проще было подключаться к устройству по SSH. Для этого редактируем файл interfaces:
nano /etc/network/interfaces

В моём случае он стал выглядеть вот так:
# interfaces(5) file used by ifup(8) and ifdown(8)
auto lo
iface lo inet loopback

# The primary network interface
allow-hotplug eth0
iface eth0 inet static
address   192.168.48.27
netmask   255.255.255.0
gateway   192.168.48.1
network   192.168.48.0
broadcast 192.168.48.255

auto eth0

10. Редактируем файл resolv.conf — чтобы нормально работал DNS-клиент:
nano /etc/resolv.conf

Добавляем в него строки:
nameserver 192.168.48.1
nameserver 8.8.8.8

11. Перезагружаем устройство.

12. Для проверки, что всё сделано правильно
подключаемся к устройству по SSH через Ethernet:



Всем спасибо за внимание!
Tags:
Hubs:
+19
Comments 4
Comments Comments 4

Articles