Crearea unei imagini Ubuntu pentru ARM „de la zero”

Când dezvoltarea abia începe, de multe ori nu este clar ce pachete vor merge la rădăcinile țintă.

Cu alte cuvinte, este prea devreme să apuci LFS, buildroot sau yocto (sau altceva), dar trebuie deja să începi. Pentru cei bogați (am 4GB eMMC pe mostre-pilot) există o cale de a distribui dezvoltatorilor o distribuție care le va permite să livreze rapid ceva care lipsește în prezent și apoi putem oricând să colectăm liste de pachete și să creăm o listă pentru rădăcinile țintă.

Acest articol nu este nou și este o simplă instrucțiune de copiere-lipire.

Scopul articolului este de a construi rootf-uri Ubuntu pentru plăci ARM (în cazul meu, pe baza Colibri imx7d).

Construirea unei imagini

Asamblam rădăcinile țintă pentru replicare.

Despachetarea bazei Ubuntu

Alegem noi înșine eliberarea în funcție de nevoi și de propriile noastre preferințe. Aici am dat 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

Verificarea suportului BINFMT în nucleu

Dacă aveți o distribuție comună, atunci există suport pentru BINFMT_MISC și totul este configurat, dacă nu, atunci sunt sigur că știți cum să activați suportul BINFMT în nucleu.

Asigurați-vă că BINFMT_MISC este activat în kernel:

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

Acum trebuie să verificați setările:

$ 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

Vă puteți înregistra manual folosind, de exemplu, iată aceste instrucțiuni.

Configurarea brațului static qemu

Acum avem nevoie de o instanță qemu asamblată static.

!!! ATENŢIE!!!
Dacă intenționați să utilizați un container pentru a construi ceva, verificați:
https://sourceware.org/bugzilla/show_bug.cgi?id=23960
https://bugs.launchpad.net/qemu/+bug/1805913
Apoi, pentru gazda x86_64 și armarea oaspeților, trebuie să utilizați versiunea i386 a 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

chroot

Script simplu:

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

Admirăm rezultatul:

$ ./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

Doar pentru distracție, să măsurăm dimensiunea înainte și după instalarea setului minim (pentru mine) de pachete:

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

Să actualizăm:

# apt update
# apt upgrade --yes

Să instalăm pachetele care ne interesează:

# 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

Fișierele și modulele antet kernel sunt o chestiune separată. Desigur, nu vom instala bootloader-ul, kernel-ul, modulele, arborele dispozitivelor prin Ubuntu. Ele vor veni la noi din exterior sau le vom asambla noi sau ne vor fi date de producătorul plăcii, în orice caz acest lucru depășește domeniul de aplicare al acestei instrucțiuni.

Într-o oarecare măsură, divergența versiunilor este acceptabilă, dar este mai bine să le luați din compilarea kernelului.

# apt install --yes linux-headers-generic

Să vedem ce s-a întâmplat și au ieșit multe:

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

Nu uitați să setați o parolă.

Împachetarea imaginii

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

În plus, putem instala etckeeper cu setarea autopush

Ei bine, să presupunem că ne-am distribuit ansamblul, a început munca pentru a asambla cel mai bine diferite versiuni ulterioare ale sistemului nostru.

etckeeper ne poate veni în ajutor.

Siguranța este o chestiune personală:

  • poți proteja anumite ramuri
  • generați o cheie unică pentru fiecare dispozitiv
  • dezactivați împingerea forțată
  • etc. ...
# ssh-keygen
# apt install etckeeper
# etckeeper init
# cd /etc
# git remote add origin ...

Să setăm autopush

Putem, desigur, să creăm ramuri pe dispozitiv în avans (să zicem că facem un script sau un serviciu care va rula prima dată când este lansat).

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

Sau putem face ceva mai inteligent...

Mod leneș

Să avem un fel de identificator unic, să spunem numărul de serie al procesorului (sau MAC - companiile serioase cumpără gama):

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

Apoi îl putem folosi pentru numele ramurii către care vom împinge:

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

Să creăm un script simplu:

# 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

Și asta este tot - după un timp putem să ne uităm la modificări și să creăm o listă de pachete pentru firmware-ul țintă.

Materiale recomandate

BINFMT_MISC
Suport kernel pentru diverse formate binare (binfmt_misc)
Compilarea cu qemu user chroot
Construirea rootf-urilor Ubuntu pentru ARM
Cum să creați un Ubuntu personalizat live de la zero
Crossdev qemu-static-user-chroot
etc pastrator

problema getdents64

readdir() returnează NULL (errno=EOVERFLOW) pentru qemu static utilizator pe 32 de biți pe gazda pe 64 de biți
Ext4 64 de biți hash breaks 32 de biți glibc 2.28+
compiler_id_detection eșuează pentru armhf când se utilizează emularea în modul utilizator QEMU
CMake nu funcționează corect sub qemu-arm

Sursa: www.habr.com