إنشاء صورة Ubuntu لـ ARM "من الصفر"

عندما يبدأ التطوير للتو، غالبًا ما يكون من غير الواضح أي الحزم ستذهب إلى الجذور المستهدفة.

بمعنى آخر، من السابق لأوانه الحصول على LFS أو buildroot أو yocto (أو أي شيء آخر)، ولكن عليك أن تبدأ بالفعل. بالنسبة للأثرياء (لدي 4 غيغابايت من eMMC في العينات التجريبية) هناك طريقة لتوزيع توزيع على المطورين يتيح لهم تسليم شيء مفقود حاليًا بسرعة، ومن ثم يمكننا دائمًا جمع قوائم الحزم وإنشاء قائمة لـ الجذور المستهدفة

هذه المقالة ليست جديدة وهي عبارة عن تعليمات بسيطة للنسخ واللصق.

الغرض من هذه المقالة هو إنشاء جذور Ubuntu للوحات ARM (في حالتي، استنادًا إلى Colibri imx7d).

بناء الصورة

نقوم بتجميع rootfs الهدف للنسخ المتماثل.

تفريغ قاعدة أوبونتو

نختار الإصدار بأنفسنا بناءً على حاجتنا وتفضيلاتنا. هنا أعطيت 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

التحقق من دعم BINFMT في النواة

إذا كان لديك توزيع مشترك، فهناك دعم لـ BINFMT_MISC وتم تكوين كل شيء، إذا لم يكن الأمر كذلك، فأنا متأكد من أنك تعرف كيفية تمكين دعم BINFMT في النواة.

تأكد من تمكين BINFMT_MISC في النواة:

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

أنت الآن بحاجة إلى التحقق من الإعدادات:

$ 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

يمكنك التسجيل يدويًا باستخدام، على سبيل المثال، هنا هذه التعليمات.

إعداد ذراع qemu الثابتة

نحن الآن بحاجة إلى مثيل qemu مُجمَّع بشكل ثابت.

!!! انتباه!!!
إذا كنت تخطط لاستخدام حاوية لبناء شيء ما، فراجع:
https://sourceware.org/bugzilla/show_bug.cgi?id=23960
https://bugs.launchpad.net/qemu/+bug/1805913
ثم بالنسبة لمضيف x86_64 وضيف الذراع، فإنك تحتاج إلى استخدام إصدار i386 من 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

الاستجذار

نص بسيط:

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

نحن معجبون بالنتيجة:

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

من أجل المتعة فقط، دعونا نقيس الحجم قبل وبعد تثبيت الحد الأدنى (بالنسبة لي) من مجموعة الحزم:

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

دعونا تحديث:

# apt update
# apt upgrade --yes

لنقم بتثبيت الحزم التي نهتم بها:

# 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

تعتبر ملفات ووحدات رأس Kernel مسألة منفصلة. بالطبع، لن نقوم بتثبيت أداة تحميل التشغيل والنواة والوحدات النمطية وشجرة الأجهزة عبر Ubuntu. سوف تأتي إلينا من الخارج أو سنقوم بتجميعها بأنفسنا أو سيتم إعطاؤها لنا من قبل الشركة المصنعة للوحة، وفي أي حال فإن هذا خارج نطاق هذه التعليمات.

إلى حد ما، يعد اختلاف الإصدار مقبولا، ولكن من الأفضل أخذه من بناء النواة.

# apt install --yes linux-headers-generic

دعونا نرى ما حدث واتضح الكثير:

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

لا تنسى تعيين كلمة المرور.

تعبئة الصورة

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

بالإضافة إلى ذلك، يمكننا تثبيت برنامج etckeeper باستخدام إعداد الدفع التلقائي

حسنًا، لنفترض أننا قمنا بتوزيع مجموعتنا، وبدأ العمل حول أفضل السبل لتجميع الإصدارات المختلفة اللاحقة من نظامنا.

يمكن لـ etckeeper أن يأتي لمساعدتنا.

السلامة مسألة شخصية:

  • يمكنك حماية فروع معينة
  • إنشاء مفتاح فريد لكل جهاز
  • تعطيل دفع القوة
  • إلخ. ...
# ssh-keygen
# apt install etckeeper
# etckeeper init
# cd /etc
# git remote add origin ...

لنقم بإعداد الدفع التلقائي

يمكننا بالطبع إنشاء فروع على الجهاز مسبقًا (لنفترض أننا أنشأنا برنامجًا نصيًا أو خدمة سيتم تشغيلها عند تشغيلها لأول مرة).

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

أو يمكننا أن نفعل شيئًا أكثر ذكاءً ...

طريقة كسول

دعونا نحصل على نوع من المعرف الفريد، مثل الرقم التسلسلي للمعالج (أو MAC - الشركات الجادة تشتري النطاق):

القط / 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

ثم يمكننا استخدامه لاسم الفرع الذي سندفع إليه:

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

لنقم بإنشاء برنامج نصي بسيط:

# 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

وهذا كل شيء - بعد فترة من الوقت يمكننا إلقاء نظرة على التغييرات وإنشاء قائمة بالحزم الخاصة بالبرامج الثابتة المستهدفة.

المواد الموصى بها

BINFMT_MISC
دعم Kernel للتنسيقات الثنائية المتنوعة (binfmt_misc)
التجميع باستخدام chroot مستخدم qemu
إنشاء جذر Ubuntu لـ ARM
كيفية إنشاء Ubuntu مخصص مباشر من البداية
Crossdev qemu-static-user-chroot
etckeeper

مشكلة getdents64

تقوم readdir() بإرجاع NULL (errno=EOVERFLOW) لـ qemu المستخدم الثابت 32 بت على مضيف 64 بت
Ext4 64 بت يكسر التجزئة 32 بت glibc 2.28+
يفشل برنامج Compiler_id_detection لـarmhf عند استخدام مضاهاة وضع المستخدم QEMU
CMake لا يعمل بشكل صحيح تحت qemu-arm

المصدر: www.habr.com