コグノスケ


link 未来から過去へ表示  link 過去から未来へ表示(*)

link もっと前
2024年8月7日 >>> 2024年8月20日
link もっと後

2024年8月7日

Debian独自の挙動をするQEMUとbinfmt_misc

目次: Linux

前回はbinfmt_miscの使い方や動作を調べました。今回はDebian特有の挙動を見ていきたいと思います。細かいことを言えばQEMUの実装の話でありbinfmt_miscの実装ではありません。しかし二者は密接に関わっているので関連項目として取り上げます。

Debianのbinfmt_miscの設定では、インタープリターに/usr/libexec/qemu-binfmt/以下のファイルを指定します。このディレクトリには独特なファイル名(例: (arch名)-binfmt-P)のシンボリックリンクが置かれています。一例を紹介します。

(arch名)-binfmt-Pの例、RISC-V 64bit向け
$ ls -la /usr/libexec/qemu-binfmt/riscv64-binfmt-P

lrwxrwxrwx 1 root root 29 May 20 22:14 /usr/libexec/qemu-binfmt/riscv64-binfmt-P -> ../../bin/qemu-riscv64-static

この/usr/libexec/qemu-binfmt/riscv64-binfmt-Pはシンボリックリンクで、実体はQEMU(/usr/bin/qemu-riscv64-static)であることが解ると思います。引数を何も指定せずに実行すると普通のQEMUとは異なるメッセージを出力します。

引数を指定せずに実行したときのエラーメッセージ
$ /usr/libexec/qemu-binfmt/riscv64-binfmt-P

qemu: /usr/libexec/qemu-binfmt/riscv64-binfmt-P has to be run using kernel binfmt-misc subsystem

メッセージを出力しているのは見た通りQEMUです、が、オリジナルのQEMUにこのメッセージを出すコードはありません。

Debianスペシャルなエラーメッセージ

Debianのqemu-user-staticパッケージソースコードを見るとこのエラーメッセージを表示するためのパッチがありました。

DebianのQEMUパッチの一部

// qemu/debian/patches/linux-user-binfmt-P.diff

diff --git a/linux-user/main.c b/linux-user/main.c
index e44bdb17b8..587bd02db2 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -562,7 +562,7 @@ static void usage(int exitcode)
     exit(exitcode);
 }
 
-static int parse_args(int argc, char **argv)
+static int parse_args(int argc, char **argv, bool *preserve_argv0)
 {
     const char *r;
     int optind;
@@ -579,6 +579,28 @@ static int parse_args(int argc, char **argv)
         }
     }
 
+    /* HACK alert.
+     * when run as an interpreter using kernel's binfmt-misc mechanism,
+     * we have to know where are we (our own binary), where's the binary being run,
+     * and what it's argv[0] element.
+     * Only with the P interpreter flag kernel passes all 3 elements as first 3 argv[],
+     * but we can't distinguish if we were run with or without this P flag.
+     * So we register a special name with binfmt-misc system, a name which ends up
+     * in "-binfmt-P", and if our argv[0] ends up with that, we assume we were run
+     * from kernel's binfmt with P flag and our first 3 args are from kernel.
+     */
+    if (strlen(argv[0]) > sizeof("binfmt-P") &&
+        strcmp(argv[0] + strlen(argv[0]) - sizeof("binfmt-P"), "-binfmt-P") == 0) {
+        if (argc < 3) {
+            (void) fprintf(stderr, "qemu: %s has to be run using kernel binfmt-misc subsystem\n", argv[0]);    //★★エラーメッセージ★★
+            exit(EXIT_FAILURE);
+        }
+        exec_path = argv[1];
+        handle_arg_argv0(argv[2]);
+        *preserve_argv0 = true;
+        return 2;
+    }
+
     optind = 1;
     for (;;) {
         if (optind >= argc) {

コマンド名の末尾が-binfmt-Pであり、引数が3つより少ない場合にエラーを出す実装です。引数を渡すか、シンボリックリンクをリネームして実行するとエラーメッセージは出現しなくなります。

シンボリックリンクをリネームした場合の挙動
# ls -la riscv64-binfmt-P_

lrwxrwxrwx 1 root root 29 May 20 22:14 riscv64-binfmt-P_ -> ../../bin/qemu-riscv64-static

# ./riscv64-binfmt-P_

qemu: no user program specified

# ../../bin/qemu-riscv64-static

qemu: no user program specified

QEMUで実行するbinfmt_miscのバイナリタイプ設定はこんな感じで、

binfmt_miscの設定例
# less /usr/lib/binfmt.d/qemu-riscv64.conf

:qemu-riscv64:M::\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/libexec/qemu-binfmt/riscv64-binfmt-P:OCPF

# ★FlagsはO, C, P, Fの4つ★

実装のコメントを見る限り、下記の条件を満たすことを期待しています。

  • シンボリックリンクの名前が必ず-binfmt-Pで終わる
  • P flagを指定するので必ず引数が3つ以上ある

この条件から外れる場合はエラーにしたいようです。riscv64-binfmt-Pのリンク先の実体はQEMUですが、間違ってQEMUとして起動することを防いでいる……?そこまでする理由があまり思いつかないですけど、昔に何かあったのかな?

編集者:すずき(2024/08/09 22:52)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2024年8月10日

Linuxを調べる - initrdとカーネル引数

目次: Linux

今どき(?)のinitrdとカーネル引数の渡し方を知らなかったのでメモしておきます。

昔のARM LinuxですとATAGと呼ばれるブートの情報を並べたリストをメモリ領域に置いてカーネル引数やinitrdを渡して(ATAGの仕様はVincentさんのBooting ARM Linuxが詳しいです)いました。ATAGは今も使えます(Booting ARM Linuxの4a. Setup the kernel tagged list)けど主流はデバイスツリーのはずです。たぶん。ARM Linuxの場合レジスタに指定すべき情報はこんな感じだそうです。

  • r0: 0
  • r1: machine type number discovered in (3) above
  • r2: physical address of tagged list in system RAM, or physical address of device tree block (dtb) in system RAM

RISC-V Linuxの場合はカーネルのドキュメント(RISC-V Kernel Boot Requirements and Constraints)によれば、RISC-V Linuxの場合レジスタに指定すべき情報はこんな感じだそうです。

  • $a0 to contain the hartid of the current core.
  • $a1 to contain the address of the devicetree in memory.

ARM Linuxよりさらに減ってhartidとデバイスツリーのアドレスのたった2つです、シンプルですね。

デバイスツリーの例

仕様からデバイスツリーを書いても良いですが、目の前のQEMUでDebianが動作している2024年8月2日の日記参照)のですから実際に動作しているものを調べたほうが早いでしょう。

QEMUが内部で生成しているデバイスツリーのダンプ方法は以前(2024年7月23日の日記参照)紹介した通りです。initrdとappend="root=/dev/nfs"を渡してQEMUを起動し、デバイスツリーをダンプして&dtsに変換します。

QEMUの自動生成したデバイスツリーブロブ(dtb)のダンプ方法
$ qemu-system-riscv64 \
  -machine virt \
  -bios none \
  -chardev stdio,id=con,mux=on \
  -serial chardev:con \
  -smp 4 \
  -kernel fw_payload.bin \
  -initrd initramfs.cpio \
  -append "root=/dev/nfs"

(QEMUモニターにて) dumpdtb virt_initrd_cmd.dtb

$ dtc -O dts virt_initrd_cmd.dtb > virt_initrd_cmd.dts
ダンプしたデバイスツリーのコード

/* virt_initrd_cmd.dts */

/dts-v1/;

/ {

...

	chosen {
		bootargs = "root=/dev/nfs";           /* ★appendで渡したカーネル引数★ */
		linux,initrd-end = <0x84227600>;      /* ★initrd終端アドレス★ */
		linux,initrd-start = <0x84000000>;    /* ★initrd先頭アドレス★ */
		stdout-path = "/soc/serial@10000000";
		rng-seed = <0x2a0a5693 0x41742b2a 0x49faf2f1 0xaf1d27cc 0x9c06cb87 0x277e3472 0xfdf688c7 0x5029079c>;
	};

...

ルートノード以下のchosenノードにあるbootargs, linux,initrd-なんとかがappendやinitrdオプションと対応しています。

  • bootargs: appendオプションに指定したカーネル引数
  • linux,initrd-start: initrdオプションに指定したファイルをロード(QEMUがやってくれる)した領域の「先頭」アドレス
  • linux,initrd-end: initrdオプションに指定したファイルをロード(QEMUがやってくれる)した領域の「終端」アドレス

以上、今どきのLinuxに対してカーネル引数やinitrdを渡す方法がわかりました。Linuxでデバイスツリーに対応したアーキテクチャは多いですから、一度実装しておけば多数のアーキテクチャでカーネルパラメーター指定ができます。便利ですね。

欠点はブートローダーでデバイスツリーのchosenノードを変更する必要がある、すなわちブートローダーにデバイスツリーを加工する処理を実装しなければならない点です。難しくはないでしょうけど、それなりに手間が掛かるでしょう。

ちなみにlinux,initrd-startのようなlinux,で始まるプロパティの仕様はLinuxカーネルのドキュメント(The chosen node - kernel.org)に記載があります。

QEMUのappend引数なしでカーネル引数を渡す実験

先程まで見てきたbootargsやinitrd-なんとかが正しく生成できれば、QEMUのappendやinitrdオプション無しでもカーネル引数やinitrdをカーネルに渡すことができるはずです。やってみましょう。

デバイスツリーのchosenノードにbootargsを追加
/* virt_mod.dts */

/dts-v1/;

/ {

...

	chosen {
		/* ★この行を追加する★ */
		bootargs = "root=/dev/nfs nfsroot=192.168.1.1:/path/to/debian_rootfs,v3 ip=on nfsrootdebug rw";

...

以前作成したGDBスクリプト(2024年7月29日の日記参照)を使ってカーネルとデバイスツリーをロードします。

デバイスツリーとOpenSBIをロードし、レジスタを設定するGDBスクリプト(再掲)
# load_dtb_opensbi.gdb

restore virt_mod.dtb binary 0x87f00000
thread 1
set $a1=0x87f00000
thread 2
set $a1=0x87f00000
thread 3
set $a1=0x87f00000
thread 4
set $a1=0x87f00000

restore fw_payload.bin binary 0x80000000
thread 1
set $pc=0x80000000
thread 2
set $pc=0x80000000
thread 3
set $pc=0x80000000
thread 4
set $pc=0x80000000

QEMUをkernel, dtb, append引数なし、-Sオプション付き(デバッガーのアタッチ待ち)で起動します。

QEMU起動、GDBスクリプトによるカーネルとデバイスツリーのロード
$ qemu-system-riscv64 \
  -machine virt \
  -bios none \
  -nographic \
  -chardev stdio,id=con,mux=on \
  -serial chardev:con \
  -mon chardev=con,mode=readline \
  -netdev user,id=netdev0 \
  -device virtio-net-device,netdev=netdev0 \
  -m 2g \
  -smp 4 \
  -s \
  -S

$ riscv64-unknown-linux-gnu-gdb

(gdb) target remote :1234

Remote debugging using :1234
warning: No executable has been specified and target does not support
determining executable automatically.  Try using the "file" command.
0x0000000000001000 in ?? ()

(gdb) source load_dtb_opensbi.gdb

Restoring binary file virt_mod.dtb into memory (0x87f00000 to 0x87f01cb5)
[Switching to thread 1 (Thread 1.1)]
#0  0x0000000000001000 in ?? ()
[Switching to thread 2 (Thread 1.2)]
#0  0x0000000000001000 in ?? ()
[Switching to thread 3 (Thread 1.3)]
#0  0x0000000000001000 in ?? ()
[Switching to thread 4 (Thread 1.4)]
#0  0x0000000000001000 in ?? ()

Restoring binary file fw_payload.bin into memory (0x80000000 to 0x81f51608)
[Switching to thread 1 (Thread 1.1)]
#0  0x0000000000001000 in ?? ()
[Switching to thread 2 (Thread 1.2)]
#0  0x0000000000001000 in ?? ()
[Switching to thread 3 (Thread 1.3)]
#0  0x0000000000001000 in ?? ()
[Switching to thread 4 (Thread 1.4)]
#0  0x0000000000001000 in ?? ()

(gdb) continue

Continuing.

最後のcontinueを実行するとQEMU側もログが出ます。例えばこんな感じです。

Debian RISC-V 64bit版の起動例
$ qemu-system-riscv64 \
  -machine virt \
  -bios none \
  -nographic \
  -chardev stdio,id=con,mux=on \
  -serial chardev:con \
  -mon chardev=con,mode=readline \
  -netdev user,id=netdev0 \
  -device virtio-net-device,netdev=netdev0 \
  -m 2g \
  -smp 4 \
  -s \
  -S

OpenSBI v1.5
   ____                    _____ ____ _____
  / __ \                  / ____|  _ \_   _|
 | |  | |_ __   ___ _ __ | (___ | |_) || |
 | |  | | '_ \ / _ \ '_ \ \___ \|  _ < | |
 | |__| | |_) |  __/ | | |____) | |_) || |_
  \____/| .__/ \___|_| |_|_____/|____/_____|
        | |
        |_|

Platform Name             : riscv-virtio,qemo
Platform Features         : medeleg

...

Boot HART MIDELEG         : 0x0000000000001666
Boot HART MEDELEG         : 0x0000000000f0b509
[    0.000000] Linux version 6.9.0 (katsuhiro@blackbird) (riscv64-unknown-linux-gnu-gcc (GCC) 14.1.0, GNU ld (GNU Binutils) 2.42.50.20240622) #9 SMP Thu Aug  1 00:38:49 JST 2024
[    0.000000] random: crng init done
[    0.000000] Machine model: riscv-virtio,qemo

...

[    2.652369] VFS: Mounted root (nfs filesystem) on device 0:20.
[    2.661913] devtmpfs: mounted
[    2.831443] Freeing unused kernel image (initmem) memory: 2260K
[    2.833459] Run /sbin/init as init process
[    4.984017] systemd[1]: systemd 256.4-2 running in system mode (+PAM +AUDIT +SELINUX +APPARMOR +IMA +SMACK +SECCOMP +GCRYPT -GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN +IPTC +KMOD +LIBCRYPTSETUP +LIBCRYPTSETUP_PLUGINS +LIBFDISK +PCRE2 +PWQUALITY +P11KIT +QRENCODE +TPM2 +BZIP2 +LZ4 +XZ +ZLIB +ZSTD +BPF_FRAMEWORK -XKBCOMMON +UTMP +SYSVINIT +LIBARCHIVE)
[    4.988413] systemd[1]: Detected virtualization qemu.
[    4.989856] systemd[1]: Detected architecture riscv64.

Welcome to Debian GNU/Linux trixie/sid!

[    5.048884] systemd[1]: Hostname set to <qemu>.

...

[  OK  ] Reached target graphical.target - Graphical Interface.
         Starting systemd-update-utmp-runle…- Record Runlevel Change in UTMP...
[  OK  ] Finished systemd-update-utmp-runle…e - Record Runlevel Change in UTMP.

Debian GNU/Linux trixie/sid qemu ttyS0

qemu login: 

Debianのログインプロンプトまで表示されれば成功です。カーネル引数を変えたりinitrdのサイズが変わるたびにdtsを書き換えてdtcでコンパイルする……なんて考えると面倒くさいことこの上ないですが、QEMUや気の利いたブートローダーは自動的にデバイスツリーのchosenノードを加工してくれます。ありがたいですね。

編集者:すずき(2024/08/12 16:23)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2024年8月11日

Amazonマイリストへの問い合わせの返事がきた

目次: Kindle

先日(2024年8月4日の日記参照)Amazonへ問い合わせた、マイリストの変な挙動についてお返事が来ていました。

Amazonからのお返事
お客様からお問い合わせいただいた件につきまして、担当部署へ報告させていただき、
問題が確認された場合には適切に対応させていただきます。

大変お手数ですが、所有数を手動で変更し、購入済に移動していただきますようお願いいたします。

なおほしい物リストの商品登録数について、1つのアカウントで管理できるデータ量には制限があります。
各リストには、登録できる最大数は2500点となりますが、サーバーに負荷をかけずに利用いただく理想の
商品数はおよそ100件となります。それを超えると、データ容量超過でスムーズに作動しない場合や、
エラーメッセージが表示される等の問題が生じる場合がございますので、それぞれのリストの登録商品が
100件以内に収まるようリストを分けて作成いただきますようお願いいたします。

不具合かどうかわからないまま終わりましたけど、本当に不具合ならAmazonのエンジニアが直すでしょう。たぶん。あとマイリストの理想の商品数なんて全く関係ない豆知識を授けてくれたのはなぜでしょうね。「お前はリストに登録し過ぎだ、変なエラーが起きても不思議じゃない」と揶揄したかった?のでしょうか。

編集者:すずき(2024/09/22 00:14)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2024年8月13日

Debianのミラーを作ってみる

目次: apt

Debianアーカイブのミラーを試してみた(Debianアーカイブミラーの構築 - Debian)のでメモです。

Debianミラーを作成するにはftpsyncスクリプトを使用します。

ftpsyncを取得する
$ wget https://ftp-master.debian.org/ftpsync.tar.gz

$ tar xf ftpsync.tar.gz
$ ls

distrib

$ tree distrib/

distrib/
|-- README.md
|-- bin
|   |-- ftpsync
|   |-- ftpsync-cron
|   |-- rsync-ssl-tunnel
|   `-- runmirrors
|-- doc
|   |-- ftpsync-cron.1.md
|   |-- ftpsync.1.md
|   |-- ftpsync.conf.5.md
|   |-- rsync-ssl-tunnel.1.md
|   |-- runmirrors.1.md
|   |-- runmirrors.conf.5.md
|   `-- runmirrors.mirror.5.md
`-- etc
    |-- ftpsync.conf.sample
    |-- runmirrors.conf.sample
    `-- runmirrors.mirror.sample

4 directories, 15 files

アーカイブにはdistribディレクトリだけ存在しています。設定する際はdistrib/etcの下にftpsync.confファイルを置きます。distrib/etcディレクトリにあるftpsync.con.sampleが設定ファイルのサンプルです。

ftpsync.confの例

# distrib/etc/ftpsync.conf

TO=/path/to/debian

RSYNC_HOST=ftp.jp.debian.org
RSYNC_PATH="debian"

ARCH_INCLUDE="riscv64"

RISC-V用のDebianアーカイブを日本のサーバーからミラーする設定は上記の通りです。実行はdistrib/bin/ftpsyncを実行するだけです。数時間かかりますが、進捗やステータスの類が何も表示されないので不安になります……。

編集者:すずき(2024/08/17 16:04)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link もっと前
2024年8月7日 >>> 2024年8月20日
link もっと後

管理用メニュー

link 記事を新規作成

<2024>
<<<08>>>
----123
45678910
11121314151617
18192021222324
25262728293031

最近のコメント5件

  • link 14年6月13日
    2048player...さん (09/26 01:04)
    「最後に、この式を出すのに紙4枚(A4)も...」
  • link 14年6月13日
    2048playerさん (09/26 01:00)
    「今のところ最も簡略化した式です。\n--...」
  • link 14年6月13日
    2048playerさん (09/16 01:00)
    「返信ありがとうございます。\nコメントが...」
  • link 14年6月13日
    すずきさん (09/12 21:19)
    「コメントありがとうございます。同じ結果に...」
  • link 14年6月13日
    2048playerさん (09/08 17:30)
    「私も2048の最高スコアを求めたのですが...」

最近の記事3件

  • link 24年9月14日
    すずき (09/22 11:23)
    「[OpenSBIを調べる - scratch領域の詳細] 目次: Linux今回はOpenSBIのコード内に頻出するscrat...」
  • link 21年8月11日
    すずき (09/22 00:15)
    「[Kindle - まとめリンク] 目次: Kindle初代Kindle Fire HDの話。Kindle Fire HDのカ...」
  • link 24年8月11日
    すずき (09/22 00:14)
    「[Amazonマイリストへの問い合わせの返事がきた] 目次: Kindle先日(2024年8月4日の日記参照)Amazonへ問...」
link もっとみる

こんてんつ

open/close wiki
open/close Linux JM
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 2022年
open/close 2023年
open/close 2024年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDFファイル RSS 1.0

最終更新: 09/26 01:04