Pylone Blog - 2007年11月

initramfs作成支援スクリプト

About

Linux起動時にinitramfsを使用するためには、 以下のいずれかを用意する必要があります。

  • 所定の形式のcpioアーカイブ
  • 展開済みのディレクトリ
  • usr/gen_init_cpio 用の設定スクリプト

このうち「usr/gen_init_cpio用の設定スクリプト」を使えると、ユーザ権限で作業ができるため、作業環境の扱いが簡単になります。

しかし、きちんと(間接的に必要となるライブラリ等まで考慮して)スクリプトを記述するのはそれなりの手間がかかり、使いこなすには経験が必要でした。

この作業の支援用として、実行可能ファイルに必要なライブラリ等の情報を抽出して設定スクリプトの雛形を生成するツールを公開します。

使いかた

ダウンロード

以下のリンク先から取得してください:

gen_init_cpio_conf.py

実行には python および binutils が必要です。

前準備

適当なディレクトリ以下に、initramfsに含めたいファイルを全て展開します。この段階では不要なファイルが含まれていても構わないので、手順としては

  1. 関連するパッケージを dpkg -x で展開
  2. その他のファイルをコピー

などとすればよいでしょう。

設定ファイル作成

最終的にinitramfsに含めたいファイルのリストを用意します。

例)FOO.def として

/bin/busybox
/bin/brcrl

誤認識されないなら、パスのディレクトリ部分(/usr/bin)は省略することができます。

busybox
brctl
スクリプトの実行

本スクリプトを「-l」 オプションにファイルリスト、続けて作業用の(ファイル一式を展開しておいた)ディレクトリのフルパスを指定して実行すると 、initramfs用の設定内容が作成されます。

$ gen_init_cpip_conf.py -l FOO.def /path/to/work/dir  > initramfs_script

作業用ディレクトリには、Linuxカーネル構築時に正しく参照が解決できるなら、相対パスを使用することもできます。

可視化

例えば、busybox, Xサーバ, matchbox について、実行に必要なライブラリとシンボリックリンクの関係は以下のようになりました。

[image]

高解像度版 (PNG) 原図 (SVG)

クロス開発環境のDebianパッケージ

社内で使っているクロス開発環境のDebianパッケージを公開します。

更新履歴

  • 2007/11/09: 公開
  • 2007/12/15: apt-lineのtypoを修正
  • 2008/02/26: update-alternativesについての記述を追加
  • 2008/07/04: mipsel で gcc-4.1 の動作を確認
  • 2008/12/22: アーカイブの鍵についての記述を追加
  • 2009/03/09: powerpc で動作を確認

概要

  • ホストアーキテクチャ: i386
  • ターゲットアーキテクチャ: arm, mipsel, powerpc, sh4
  • コンパイラ: gcc-3.4, gcc-4.1, g++-4.1
  • glibc: 2.3.6 (etch の glibc)
  • ssp: 無効

基本的にはetchのbinutils, gccを debian/README.cross等の手順通りにビルドしたものですが、 etchとsidの両方にインストールできるように依存関係を調整するなど 若干の変更を加えています。

対応状況

gcc-3.4 gcc-4.1 g++-4.1
arm
mipsel
powerpc × ×
sh4
  • ○:動作を確認したもの
  • △:パッケージはあるが、まだ動作が確認できていないもの
  • ×:まだパッケージが用意できていないもの

インストール

etchかsidであればインストールできる筈です。

/etc/apt/sources.listに以下のapt lineを加えます。

deb http://downloads.pylone.jp/cross-toolchain/deb ./

アーカイブの鍵を導入します。

# wget http://pylone.jp/pubkey.asc -O - | apt-key add -

パッケージ情報を更新します。

# aptitude update

必要なツールをインストールします。 ARCHはarm、mipsel、sh4、powerpcの何れかに置き換えてください。

gcc-3.4
# aptitude install gcc-3.4-ARCH-linux-gnu
gcc-4.1
# aptitude install gcc-4.1-ARCH-linux-gnu
g++-4.1
# aptitude install g++-4.1-ARCH-linux-gnu
※ powerpc用g++はまだ用意できていません。
gdb
# aptitude install gdb-ARCH-linux-gnu
gcc-3.4とgcc-4.1の切り替え
# update-alternatives --config ARCH-linux-gnu-gcc

リンク

謝辞

sh4用glibcをビルドするにあたって、シリコンリナックス株式会社様が公開されているglibcパッケージのdebian/patches/sh/*.diffを使わせて頂きました。

ディスクイメージのホスト側での操作方法

QEMUなどのシステムエミュレータでは、エミュレートされるシステムに対して仮想的なデバイスを見せることができます。 ハードディスクなどの記憶装置を模擬する場合、ディスクイメージをファイルとして作成して使うことが多いでしょう。

今回は、このディスクイメージを仮想環境の外側で作成/操作する手段について紹介します。

作業環境としてはLinuxを想定しています。

イメージの作成

希望の構成のディスクイメージを、ホスト環境で作成する手順を説明します。

ファイル作成

まず希望のデバイスサイズのファイルを用意します。

サイズさえ十分ならどのようにしても構いませんが、ddで作ることをおすすめします。例えば 512 MBytes のものを作りたいなら

$ dd if=/dev/zero of=FILENAME bs=1 count=1 seek=536870911

とするとよいでしょう。 (seek= の値は、512 MBytes = 524288 KBytes = 536870912 Byte なので、536870912-1 を指定しています)

素朴に /dev/zero からコピーして

$ dd if=/dev/zero of=FILENAME bs=1M count=512

としてもよいのですが、近代的な(ファイルにholeが作れる)ファイルシステムで作業しているならseek させた方が 終了が早く、実ディスク消費も抑えられます。

パーティション作成

エミュレーションされる環境を実際の環境に近付けるために、ディスクイメージ上にはパーティションが作成されている状態を用意できると便利です。そこで、ループバックデバイスを用いてファイルをブロックデバイスとして見せ、fdisk などの対象に取れるようにする方法について説明します。

パーティションを作成する必要がないなら、ディスクイメージに対してmkfsを実行すれば十分なので、この節の内容は不要です。

まず、losetupを用いてファイルをループバックデバイスに結びつけます。この操作にはroot権限が必要です。

# losetup /dev/loop0 FILENAME

losetupに成功すると、/dev/loop0がFILENAMEを内容とするブロックデバイスとして振る舞うようになります。

何らかの理由でloop0が使用中の場合は、適宜loop1などに読みかえてください。

ループバックデバイスに対してfdiskを実行します。後の作業で各パーティションの開始セクタ番号が必要になるので、-uオプションを付けておきます。

# fdisk -u /dev/loop0
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel with disk identifier 0xaf87fef0.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable.

Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)

パーティションを作成します。この例では一つだけ作ります。

Command (m for help): n
First sector (63-1048575, default 63):
Using default value 63
Last sector or +size or +sizeM or +sizeK (63-1048575, default 1048575):
Using default value 1048575

パーティションを作成したら、状態を確認します。

Command (m for help): p

Disk /dev/loop0: 536 MB, 536870912 bytes
255 heads, 63 sectors/track, 65 cylinders, total 1048576 sectors
Units = sectors of 1 * 512 = 512 bytes
Disk identifier: 0xaf87fef0

      Device Boot      Start         End      Blocks   Id  System
/dev/loop0p1              63     1048575      524256+  83  Linux
Partition 1 does not end on cylinder boundary.

表示される値のうち、「Units」の値(ここでは 512 bytes)と「Start」の値(ここでは63)を覚えておきます。

作成結果に問題なければ変更をイメージに書き戻して終了します。

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.

WARNING: Re-reading the partition table failed with error 22: Invalid argument.
The kernel still uses the old table.
The new table will be used at the next reboot.
Syncing disks.
Command (m for help): q

使いおわったらループバックデバイスを開放します。

# losetup -d /dev/loop0
イメージ内のパーティションをフォーマット

ここまでの作業でディスクイメージにパーティションを作成できましたが、まだ個々のパーティションにはファイルシステムが書かれていません。 個別のパーティションに対してmkfsを実行するための手順を説明します。

mkfsの対象とするためには、(ディスクイメージ全体ではなく)対象となるパーティションの部分を取り出す必要があります。

losetupの-oオプションを使用することで、ファイルの途中からをループバックデバイスに結びつけます。

先ほどの例では 開始位置が 63、Unit が 512 bytes だったので、パーティション#1のオフセットとして63*512=32256バイトを設定します。

# losetup -o 32256 /dev/loop0 FILENAME

losetupに成功したら、好みのファイルシステムを作成できます。

# mkfs.ext2 /dev/loop0

使いおわったらループバックデバイスを開放します。

# losetup -d /dev/loop0

イメージ内のパーティションに外からアクセス

既にファイルシステムが作られているイメージ(上記の手順で作成したものや、仮想環境で使っていたrawイメージなど)を扱う場合、 mountの"loop"オプションを使用することで、イメージ内部のパーティションを直接ホスト環境にマウントすることができます。

この例の場合、loopのoffsetに開始位置(32256)を指定する:

# mount -o loop,offset=32256 FILENAME /mnt/

と、/mnt経由で先ほど作成したパーティションの内容を操作することができるようになります。

作業が終わったら通常のmountと同じように

# umount /mnt/

します。

注意

仮想環境で使用中のイメージファイルをホスト側環境から同時に操作すると、データを失う可能性があります。

sysfs 経由でモジュールパラメータにアクセス

sysfs経由でモジュールパラメータにアクセスする方法を紹介します。

Linux-2.6でモジュールパラメータを定義するマクロがMODULE_PARMからmodule_paramに変更されました。

Linux-2.4のMODULE_PARM:

/* パラメータparamをint型で宣言 */
static int param = 0;
MODULE_PARM(param, "i");
MODULE_PARM_DESC(param, "Description");

Linux-2.6のmodule_param:

/* パラメータparamをint型で宣言 */
static int param = 0;
module_param(param, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(param, "Description");

insmodの引数として指定できるパラメータであることは同じですが、module_paramではsysfsからもパラメータにアクセスできます。

# echo 1 > /sys/module/モジュール名/parameters/param

似たようなことはprocfsでもできますが面倒です。 module_paramであればsysfsの詳細を知らなくても定義するだけでモジュール内の変数をパラメータとしてユーザ空間にexportできます。 デバッグ時など、ioctlを使うまでもない場合には便利じゃないでしょうか?

モジュールではなくカーネルにstaticリンクされててもアクセスできます。

sysfsによってファイルとして見えるパラメータのパーミッションはmodule_paramの引数で指定します。

パラメータとして使う変数が文字列の場合、module_param_string を使います。

関連記事