Créer une image Ubuntu pour ARM « à partir de zéro »

Lorsque le développement commence tout juste, il est souvent difficile de savoir quels paquets seront envoyés au rootfs cible.

En d'autres termes, il est trop tôt pour récupérer LFS, buildroot ou yocto (ou autre chose), mais vous devez déjà commencer. Pour les riches (j'ai 4 Go d'eMMC sur des échantillons pilotes), il existe un moyen de distribuer aux développeurs une distribution qui leur permettra de livrer rapidement quelque chose qui manque actuellement, et nous pourrons alors toujours collecter des listes de packages et créer une liste pour les rootfs cibles.

Cet article n’est pas nouveau et est une simple instruction copier-coller.

Le but de l'article est de créer des rootfs Ubuntu pour les cartes ARM (dans mon cas, basé sur Colibri imx7d).

Construire une image

Nous assemblons les rootfs cibles pour la réplication.

Déballage de la base Ubuntu

Nous choisissons nous-mêmes la version en fonction de nos besoins et de nos propres préférences. Ici, j'en ai donné 20.

$ mkdir ubuntu20
$ cd ubuntu20
$ mkdir rootfs
$ wget http://cdimage.ubuntu.com/ubuntu-base/releases/20.04/release/ubuntu-base-20.04-base-armhf.tar.gz
$ tar xf ubuntu-base-20.04-base-armhf.tar.gz -C rootfs

Vérification du support BINFMT dans le noyau

Si vous avez une distribution commune, alors BINFMT_MISC est pris en charge et tout est configuré, sinon, je suis sûr que vous savez comment activer la prise en charge de BINFMT dans le noyau.

Assurez-vous que BINFMT_MISC est activé dans le noyau :

$ zcat /proc/config.gz | grep BINFMT
CONFIG_BINFMT_ELF=y
CONFIG_COMPAT_BINFMT_ELF=y
CONFIG_BINFMT_SCRIPT=y
CONFIG_BINFMT_MISC=y

Vous devez maintenant vérifier les paramètres :

$ ls /proc/sys/fs/binfmt_misc
qemu-arm  register  status
$ cat /proc/sys/fs/binfmt_misc/qemu-arm
enabled
interpreter /usr/bin/qemu-arm
flags: OC
offset 0
magic 7f454c4601010100000000000000000002002800
mask ffffffffffffff00fffffffffffffffffeffffff

Vous pouvez vous inscrire manuellement en utilisant, par exemple, voici ces instructions.

Configuration du bras statique qemu

Nous avons maintenant besoin d’une instance qemu assemblée statiquement.

!!! ATTENTION!!!
Si vous envisagez d'utiliser un conteneur pour créer quelque chose, consultez :
https://sourceware.org/bugzilla/show_bug.cgi?id=23960
https://bugs.launchpad.net/qemu/+bug/1805913
Ensuite, pour l'hôte x86_64 et l'invité arm, vous devez utiliser la version i386 de qemu :
http://ftp.ru.debian.org/debian/pool/main/q/qemu/qemu-user-static_5.0-13_i386.deb

$ wget http://ftp.debian.org/debian/pool/main/q/qemu/qemu-user-static_5.0-13_amd64.deb
$ alient -t qemu-user-static_5.0-13_amd64.deb
# путь в rootfs и имя исполняемого файла должно совпадать с /proc/sys/fs/binfmt_misc/qemu-arm
$ mkdir qemu
$ tar xf qemu-user-static-5.0.tgz -C qemu
$ file qemu/usr/bin/qemu-arm-static
qemu/usr/bin/qemu-arm-static: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=be45f9a321cccc5c139cc1991a4042907f9673b6, for GNU/Linux 3.2.0, stripped
$ cp qemu/usr/bin/qemu-arm-static rootfs/usr/bin/qemu-arm
$ file rootfs/usr/bin/qemu-arm
rootfs/usr/bin/qemu-arm: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=be45f9a321cccc5c139cc1991a4042907f9673b6, for GNU/Linux 3.2.0, stripped

chrooter

Scénario simple :

ch-mount.sh

#!/bin/bash

function mnt() {
    echo "MOUNTING"
    sudo mount -t proc /proc proc
    sudo mount --rbind /sys sys
    sudo mount --make-rslave sys
    sudo mount --rbind /dev dev
    sudo mount --make-rslave dev
    sudo mount -o bind /dev/pts dev/pts
    sudo chroot 
}

function umnt() {
    echo "UNMOUNTING"
    sudo umount proc
    sudo umount sys
    sudo umount dev/pts
    sudo umount dev

}

if [ "$1" == "-m" ] && [ -n "$2" ] ;
then
    mnt $1 $2
elif [ "$1" == "-u" ] && [ -n "$2" ];
then
    umnt $1 $2
else
    echo ""
    echo "Either 1'st, 2'nd or both parameters were missing"
    echo ""
    echo "1'st parameter can be one of these: -m(mount) OR -u(umount)"
    echo "2'nd parameter is the full path of rootfs directory(with trailing '/')"
    echo ""
    echo "For example: ch-mount -m /media/sdcard/"
    echo ""
    echo 1st parameter : 
    echo 2nd parameter : 
fi

Nous admirons le résultat :

$ ./ch-mount.sh -m rootfs/
# cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal
# uname -a
Linux NShubin 5.5.9-gentoo-x86_64 #1 SMP PREEMPT Mon Mar 16 14:34:52 MSK 2020 armv7l armv7l armv7l GNU/Linux

Juste pour le plaisir, mesurons la taille avant et après l'installation de l'ensemble minimum (pour moi) de packages :

# du -d 0 -h / 2>/dev/null
63M     /

Mettons à jour :

# apt update
# apt upgrade --yes

Installons les packages qui nous intéressent :

# SYSTEMD_IGNORE_CHROOT=yes apt install --yes autoconf kmod socat ifupdown ethtool iputils-ping net-tools ssh g++ iproute2 dhcpcd5 incron ser2net udev systemd gcc minicom vim cmake make mtd-utils util-linux git strace gdb libiio-dev iiod

Les fichiers d'en-tête et les modules du noyau sont une affaire distincte. Bien entendu, nous n'installerons pas le bootloader, le noyau, les modules, l'arborescence des périphériques via Ubuntu. Ils nous viendront de l'extérieur ou nous les assemblerons nous-mêmes ou ils nous seront fournis par le fabricant de la planche, dans tous les cas cela sort du cadre de cette instruction.

Dans une certaine mesure, les divergences de versions sont acceptables, mais il est préférable de les extraire de la version du noyau.

# apt install --yes linux-headers-generic

Voyons ce qui s'est passé et cela s'est avéré beaucoup de choses :

# apt clean
# du -d 0 -h / 2>/dev/null
770M    /

N'oubliez pas de définir un mot de passe.

Emballer l'image

$ sudo tar -C rootfs --transform "s|^./||" --numeric-owner --owner=0 --group=0 -c ./ | tar --delete ./ | gzip > rootfs.tar.gz

De plus, nous pouvons installer etckeeper avec le paramètre autopush

Eh bien, disons que nous avons distribué notre assemblage, le travail a commencé sur la meilleure façon d'assembler ultérieurement différentes versions de notre système.

etckeeper peut nous venir en aide.

La sécurité est une affaire personnelle :

  • vous pouvez protéger certaines branches
  • générer une clé unique pour chaque appareil
  • désactiver la poussée forcée
  • etc. ...
# ssh-keygen
# apt install etckeeper
# etckeeper init
# cd /etc
# git remote add origin ...

Configurons la poussée automatique

On peut bien sûr créer des branches sur l’appareil à l’avance (disons que l’on crée un script ou un service qui s’exécutera au premier lancement).

# cat /etc/etckeeper/etckeeper.conf
PUSH_REMOTE="origin"

Ou nous pouvons faire quelque chose de plus intelligent...

Manière paresseuse

Ayons une sorte d'identifiant unique, par exemple le numéro de série du processeur (ou MAC - des entreprises sérieuses achètent la gamme) :

cat / proc / cpuinfo

# cat /proc/cpuinfo
processor       : 0
model name      : ARMv7 Processor rev 5 (v7l)
BogoMIPS        : 60.36
Features        : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm 
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0xc07
CPU revision    : 5

processor       : 1
model name      : ARMv7 Processor rev 5 (v7l)
BogoMIPS        : 60.36
Features        : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm 
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0xc07
CPU revision    : 5

Hardware        : Freescale i.MX7 Dual (Device Tree)
Revision        : 0000
Serial          : 06372509

Ensuite, nous pouvons l'utiliser pour le nom de la branche vers laquelle nous allons pousser :

# cat /proc/cpuinfo | grep Serial | cut -d':' -f 2 | tr -d [:blank:]
06372509

Créons un script simple :

# cat /etc/etckeeper/commit.d/40myown-push
#!/bin/sh
set -e

if [ "$VCS" = git ] && [ -d .git ]; then
  branch=$(cat /proc/cpuinfo | grep Serial | cut -d':' -f 2 | tr -d [:blank:])
  cd /etc/
  git push origin master:${branch}
fi

Et c'est tout - après un certain temps, nous pouvons examiner les modifications et créer une liste de packages pour le firmware cible.

Matériaux recommandés

BINFMT_MISC
Prise en charge du noyau pour divers formats binaires (binfmt_misc)
Compilation avec le chroot utilisateur qemu
Construire des rootfs Ubuntu pour ARM
Comment créer un Ubuntu personnalisé en direct à partir de zéro
Crossdev qemu-static-user-chroot
etc.gardien

problème getdents64

readdir() renvoie NULL (errno=EOVERFLOW) pour un qemu statique utilisateur 32 bits sur un hôte 64 bits
Le hachage Ext4 64 bits casse la glibc 32 bits 2.28+
compiler_id_detection échoue pour armhf lors de l'utilisation de l'émulation en mode utilisateur QEMU
CMake ne fonctionne pas correctement sous qemu-arm

Source: habr.com