ARM 用の Ubuntu イメージを「最初から」作成する

開発が始まったばかりのときは、どのパッケージがターゲット rootfs に移されるかが明確でないことがよくあります。

言い換えれば、LFS、buildroot、yocto (またはその他) を入手するには時期尚早ですが、すでに始める必要があります。 裕福な人(私はパイロット サンプルで 4GB eMMC を持っています)には、現在不足しているものをすぐに提供できるディストリビューションを開発者に配布する方法があります。そうすれば、いつでもパッケージのリストを収集して、次のパッケージのリストを作成できます。ターゲットの rootfs。

この記事は新しいものではなく、単純なコピー&ペーストの手順です。

この記事の目的は、ARM ボード用の Ubuntu rootfs を構築することです (私の場合、Colibri imx7d に基づいています)。

イメージの構築

レプリケーション用のターゲット rootfs をアセンブルします。

Ubuntuベースの開梱

私たちは必要性と私たち自身の好みに基づいて、自分たちでリリースを選択します。 ここでは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マウント.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

カーネルヘッダーファイルとモジュールは別の問題です。 もちろん、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 - 真剣な企業が製品群を購入する) のシリアル番号を用意しましょう。

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

次に、それをプッシュ先のブランチの名前として使用できます。

# 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
さまざまなバイナリ形式のカーネル サポート (binfmt_misc)
qemu ユーザー chroot でコンパイルする
ARM 用の Ubuntu rootfs の構築
カスタムUbuntuを最初からライブで作成する方法
Crossdev qemu-static-user-chroot
etckeeper

getdents64 の問題

32 ビット ホスト上の 64 ビット ユーザー静的 Qemu の場合、readdir() が NULL (errno=EOVERFLOW) を返す
Ext4 64 ビット ハッシュ ブレーク 32 ビット glibc 2.28+
QEMU ユーザー モード エミュレーションを使用すると、armhf で COMPILER_ID_DETECTION が失敗する
CMake が qemu-arm の下で正しく動作しない

出所: habr.com