Crearea unei imagini Ubuntu pentru ARM „from scratch”

Când dezvoltarea abia a început, adesea nu este clar ce pachete vor fi incluse în rootfs-ul țintă.

Cu alte cuvinte, este prea devreme să ne apucăm de LFS, buildroot sau yocto (sau altceva), dar trebuie să începem deja. Pentru cei cu resurse (la mostrele mele am 4GB eMMC), există o soluție: să oferim dezvoltatorilor o distribuție care să permită livrarea rapidă a ce lipsește în acel moment, iar apoi putem întotdeauna să compilăm liste de pachete pentru a forma lista pentru rootfs-ul țintă.

Acest articol nu aduce nimic nou și reprezintă un simplu ghid de tip copy-paste.

Scopul articolului este construirea rootfs-ului Ubuntu pentru plăci ARM (în cazul meu, bazat pe Colibri imx7d).

Crearea imaginii

Construim rootfs-ul țintă pentru reproducere.

Dezarchivează Ubuntu Base

Alegem noi versiunea, în funcție de necesitate și preferințele personale. Aici am enumerat 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ă, suportul pentru BINFMT_MISC este inclus și totul este configurat. Dacă nu, sunt sigur că știți cum să activați suportul BINFMT în nucleu.

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

$ 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ă verificăm 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

Se poate înregistra manual, de exemplu, această instrucțiune.

Configurarea qemu static arm

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

!!! ATENȚIE!!!
Dacă doriți să folosiți un container pentru a construi un anumit lucru, consultați:
https://sourceware.org/bugzilla/show_bug.cgi?id=23960
https://bugs.launchpad.net/qemu/+bug/1805913
Atunci pentru gazdă x86_64 și invitat arm 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
# calea în rootfs și numele fișierului executabil trebuie să corespundă cu /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), linked statically, BuildID[sha1]=be45f9a321cccc5c139cc1991a4042907f9673b6, pentru 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), linked statically, BuildID[sha1]=be45f9a321cccc5c139cc1991a4042907f9673b6, pentru GNU/Linux 3.2.0, stripped

Chroot

Script simplu:

ch-mount.sh

#!/bin/bash

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

function umnt() {
    echo "UNMOUNTING"
    sudo umount ${2}proc
    sudo umount ${2}sys
    sudo umount ${2}dev/pts
    sudo umount ${2}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 : ${1}
    echo 2nd parameter : ${2}
fi

Ne admirăm rezultatul obținut:

$ .\/ch-mount.sh -m rootfs\/\n# cat \/etc\/os-release\nNAME="Ubuntu"\nVERSION="20.04 LTS (Focal Fossa)"\nID=ubuntu\nID_LIKE=debian\nPRETTY_NAME="Ubuntu 20.04 LTS"\nVERSION_ID="20.04"\nHOME_URL="https:\/\/www.ubuntu.com\/"\nSUPPORT_URL="https:\/\/help.ubuntu.com\/"\nBUG_REPORT_URL="https:\/\/bugs.launchpad.net\/ubuntu\/"\nPRIVACY_POLICY_URL="https:\/\/www.ubuntu.com\/legal\/terms-and-policies\/privacy-policy"\nVERSION_CODENAME=focal\nUBUNTU_CODENAME=focal\n# uname -a\nLinux NShubin 5.5.9-gentoo-x86_64 #1 SMP PREEMPT Mon Mar 16 14:34:52 MSK 2020 armv7l armv7l armv7l GNU\/Linux

De curiozitate, să măsurăm dimensiunea înainte și după instalarea setului minim de pachete (pentru mine):

# 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 de antet ale nucleului, modulele, sunt o discuție separată. Bootloaderul, nucleul, modulele, arborele de dispozitive nu le putem instala prin Ubuntu. Ele vor veni din exterior sau le vom compila noi înșine sau ne le va furniza producătorul plăcii, oricum, aceasta este dincolo de această instrucțiune.

Până la un punct, abaterile de versiuni sunt acceptabile, dar cel mai bine este să le luăm de la compilarea nucleului.

# apt install --yes linux-headers-generic

Să vedem ce a ieșit și a ieșit mult:

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

Nu uitați să setați parola.

Pachetăm imaginea

$ 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

Bine, să spunem că am distribuit construcția noastră, a început activitatea, cum ar fi cel mai bine să construim ulterior diferitele versiuni ale sistemului nostru.

Etckeeper ne-ar putea veni în ajutor.

Securitatea este o chestiune personală:

  • puteți proteja anumite ramuri
  • generați o cheie unică pentru fiecare dispozitiv
  • interziceți force push
  • și așa mai departe …
# ssh-keygen
# apt install etckeeper
# etckeeper init
# cd /etc
# git remote add origin ...

Să configurăm autopush

Putem, desigur, să creăm ramuri pe dispozitiv din timp (de exemplu, să facem un script sau un serviciu care să se execute la prima pornire).

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

Sau putem acționa mai ingenios…

Calea leneșului

Să avem un identificator unic, să spunem, seria procesorului (sau MAC — companiile serioase cumpără un domeniu):

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

Atunci putem folosi acest lucru ca nume pentru ramura în care vom face push:

# 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 totul — după un timp putem verifica modificările și să formăm o listă de pachete pentru firmware-ul țintă.

Materiale recomandate

BINFMT_MISC
Suport pentru Formate Binare Diverse (binfmt_misc)
Compilarea cu qemu user chroot
Construirea Ubuntu rootfs pentru ARM
Cum să creezi o versiune personalizată de Ubuntu de la zero
Crossdev qemu-static-user-chroot
etckeeper

problema getdents64

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

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster