はじめに †
本ソフトウェアはKernelの切り替えを動的に行うプログラムです。
最近、2.6カーネルが動き出したり、SH-Linuxのホームページにおいて、
SH版 Fedora Core 2 互換パッケージ等が公開されてたりして、
SH-Linux周辺に新たな動きがあります。
それらを見て、私もカーネルを変更したくなりまして。。。
しかし、LANDISKの箱を開けたくなかったのと、システムを壊してしまうのが嫌だったので、
本プログラムの作成を思い立った次第です。
なお、本ソフトウェアは、mipsマシンに実装されているakmemや
2.6カーネルで実装されるといわれるkexec等の思想をそっくりそのまま頂きました。
ソフトウェアの構成と動作概略 †
インストール †
- reboot、haltコマンドの置き換え
/sbin/rebootや、/sbin/haltは、busyboxへの相対リンクになっています。
# cd /sbin
# ls -la reboot halt
lrwxrwxrwx 1 root root 14 Mar 18 2004 halt -> ../bin/busybox
lrwxrwxrwx 1 root root 14 Mar 18 2004 reboot -> ../bin/busybox
これらのコマンドをkernelsw.plで置き換えます。
# cd /sbin
# cp kernelsw.pl . /sbinへkernelsw.plをコピー
# rm halt reboot rebootとhaltを削除
# ln -s kernelsw.pl reboot rebootへリンク
# ln -s kernelsw.pl halt haltへリンク
これで、reboot、haltコマンドが呼ばれた時、kernelsw.plが実行されるようになりました。
# ls -la reboot halt
lrwxrwxrwx 1 root root 11 Jan 5 14:57 halt -> kernelsw.pl
lrwxrwxrwx 1 root root 11 Jan 5 14:57 reboot -> kernelsw.pl
次に先ほど削除したrebootとhaltコマンドを別の場所(/sbin/reboot_org/)へ作成します。
ディレクトリが一つ深くなっているので、それにあわせて相対リンクします。
# mkdir reboot_org
# cd reboot_org
# ln -s ../../bin/busybox reboot
# ln -s ../../bin/busybox halt
これでインストールは完了です。
ルートファイルシステムをリードオンリーに戻しておきます。
# mount -o ro,remount / # read-onlyでリマウント
コマンドオプション †
- help
まずは、ヘルプです。
# kernelsw.pl -h
Usage : kernelsw.pl [ OPTION | FILE ]
"" print current status
FILE kernel setup (ex. kernelsw.pl lilo.conf)
-fswitch force switch kernel
-r remove device driver and free allocate memory
-h help
FILE format example :
image=/boot/zImage
root=/dev/hda1
read-only
append="mem=64M console=ttySC1,9600"
offset_address=0x00210000
more infomation :
http://eggplant.ddo.jp/
#
ヘルプを含み5つのオプションが実装されています。
引数は”なし”もしくは第一引数のみ有効です。
コマンドオプションを順番に説明して行きます。
- ステータス表示
オプション無しでコマンドを実行すると現在のステータスを表示します。
まだ何も設定されていないため、ほとんどの項目は0もしくは未定義値になっています。
# kernelsw.pl
==============================================
SH-Linux Kernel Switcher V2.1
----------------------------------------------
image = (size:0,page:0)
root = Not defined (read/write)
append = ""
offset_address = 0
----------------------------------------------
kernel boot parameter details
0 : 0 # read/write root file system
1 : 0 # RAMDISK Flags
2 : 0 # Root device (Not defined)
3 : 0 # Loader type (LILO = 1)
4 : 0 # Initrd start
5 : 0 # Initrd size
6 : 0 # Not defined yet
7 : 0 # Not defined yet
==============================================
- Kernel起動パラメータとKernelイメージの設定
lilo.confに準じたファイルを指定します。
指定されたファイルの内容に従い、カーネルイメージと起動パラメータをメモリ内に読み込みます。
最も重要なコマンドなので、次の節で詳しく説明します。
- 新カーネルの強制起動
"-fswitch"オプションを指定します。
通常は使用しないでください。
なぜなら、本オプションを指定すると即座にスイッチ動作が開始されるため、
実行中のプロセスは、電源が突然落ちたに等しい状態になるからです。
万が一使用する場合は、実行中のプロセスを可能な限り停止させ、
さらに、ファイルシステムを可能な限りアンマウント、もしくは、リードオンリーでリマウントした
状態で使用してください。
- クリーンな状態への戻しかた
"-r"オプションを指定します。
確保されたメモリエリアを開放すると共に、ドライバをアンロードします。
- 制限事項
- カーネルサイズの上限は、2MB(2,097,152バイト)です。
(Ver 3.2において、本制限は16MBまで拡張されました。)
- SH4アーキテクチャのみ対応しています。(LANDISKアーキテクチャと言うべきかも)
Kernel Switcherの動作確認 †
- 動作確認方法
それでは実際に、
/boot/zImage ... LANDISKオリジナルのカーネル
/dev/hda1 ....LANDISKオリジナルのルートファイルシステム
を用いてKernelのスイッチ動作を確認してみることにします。
しかし、そのままではKernel Swicherが正常に動作したかどうかわからないので、
起動パラメータを少しかえてみます。
- オリジナルの起動パラメータ
次のコマンドを実行するとカーネルの起動パラメータを確認できます。
# cat /proc/cmdline
# mem=64M console=ttySC1,9600
これによると、メモリは64Mバイト、コンソールは/dev/ttySC1、その通信速度は9600bpsに設定されていることがわかります。
それでは、メモリを1Mバイト減らしてみることにします。
64Mバイトの現在の設定では、MemTotal=62800kBとなっています。
# cat /proc/meminfo
total: used: free: shared: buffers: cached:
Mem: 64307200 62648320 1658880 0 1204224 40824832
Swap: 575758336 8261632 567496704
MemTotal: 62800 kB
- lilo.confの準備
カーネルのスイッチ動作を確認するために、わざと、appendのmemパラメータを63Mに設定してみます。
lilo.confファイルは次のようになります。
linear
boot=/dev/hda
disk=/dev/hda
bios=0x80
timeout=50
default=linux
image=/boot/zImage
label=linux
root=/dev/hda1
read-only
append="mem=63M console=ttySC1,9600"
※kernelsw.plは赤文字の部分だけを認識します。
なお、マルチラベルには対応していないので、一つのラベルだけを記述するようにしてください。
- Kernel起動パラメータとKernelイメージの設定
準備したlilo.confファイルを指定して、kernlesw.plを実行します。
# kernelsw.pl lilo.conf
Loading .... done.
==============================================
SH-Linux Kernel Switcher V2.1
----------------------------------------------
image = /boot/zImage (size:978185,page:239)
root = /dev/hda1 (read-only)
append = "mem=63M console=ttySC1,9600"
offset_address=0x00210000
----------------------------------------------
kernel boot parameter details
0 : 0x1 # read-only root file system
1 : 0x0 # RAMDISK Flags
2 : 0x301 # Root device (/dev/hda1)
3 : 0x1 # Loader type (LILO = 1)
4 : 0x0 # Initrd start
5 : 0x0 # Initrd size
6 : 0x0 # Not defined yet
7 : 0x0 # Not defined yet
==============================================
lilo.confファイルの指定に従い、カーネルイメージと起動パラメータがメモリ内に格納されました。
- Kernel Switch
この状態で、LANDISKの電源ボタンをOFFにすると、シャットダウン動作が開始されます。
そして、その最終段階で、haltコマンド(実体はkernelsw.pl)が呼び出され、カーネルのスイッチが行われます。
haltコマンド(実体はkernelsw.pl)が呼び出されると、恐らく1秒以内にLANDISKのLEDが全て消えます。
これはカーネルローダの転送が終了したことを示しています。
その後、赤いLEDが点灯します。この間、先ほど転送されたカーネルローダはカーネルの再配置を行っています。
再配置が完了すると、赤と緑の両方のLEDが点灯して、新カーネルへ制御が移ります。
ここからは、本プログラムの制御を離れ、カーネル自身のコードで動作します。
カーネルは、通常圧縮された状態にあるので、自らその圧縮をとき、ブートシーケンスを開始します。
カーネルは初期化後、ルートファイルシステムをマウントして、initプログラムを起動します。
そして、そのinitから、芋ズル式に各プログラムが起動され、最終的にtelnet等からアクセスできるようになります。
- カーネルスイッチ動作の確認
カーネルのスイッチ動作を確認するため、telnetで接続後、起動パラメータと、MemTotalの値を確認してみます。
正しく起動パラーメタが設定されており、カーネルスイッチが正常に行われたようです。
# cat /proc/cmdline
mem=63M console=ttySC1,9600
# cat /proc/meminfo
total: used: free: shared: buffers: cached:
Mem: 63270912 54775808 8495104 0 1851392 32464896
Swap: 575758336 0 575758336
MemTotal: 61788 kB
正しく動作確認できたなら、電源スイッチをON側に戻しておきましょう。
- もとのLANDISKの環境へ
電源スイッチをOFFにするとLANDISKはシャットダウン動作を開始して、
電源がOFFされます。
再度電源をONすると、もとの64MBの状態に復帰します。
- 次なる挑戦
本Kernelsw.plを用いてプレーンなdebian環境を/dev/hda3上に構築したいと考えています。
参考文献 †
- LinuxSH
SH-IPL Sequence,LILO Sequence,LinuxSH Kernel Boot Sequence等、
SH-Linuxの起動のシーケンスが非常に参考になりました。
人柱になっても良いという方へ †
非常に危険なプログラムですが、使ってみたいという方はどうぞ!
次の場所へソースを含め、一式置いておきます。
http://eggplant.ddo.jp/www/download/SH-Linux_Kernel_Switcher/
個人メモ †
- /dev/hda5等から起動するには?
- /dev/hda1〜4以外から起動させる場合は、下記吉藤さんのパッチが有効。
- 他の方法として、apppendオプションで「root=/dev/hda5」等と明示的に指定する方法もある。
吉藤さんから頂いたパッチ
diff -ru kernelsw-2.1/kernelsw.pl kernelsw-2.1-dev/kernelsw.pl
--- kernelsw-2.1/kernelsw.pl 2005-03-02 20:13:28.000000000 +0900
+++ kernelsw-2.1-dev/kernelsw.pl 2005-06-09 01:43:35.183832360 +0900
@@ -4,7 +4,11 @@
# kernelsw.pl version 2.1
# SH-Linux Kernel switcher
# http://eggplant.ddo.jp/
-
+#
+# Changes:
+# YOSHIFUJI Hideaki <yoshfuji at linux-ipv6.org>
+# support more root devices
+#
$version = '2.1';
$real_reboot_dir = '/sbin/reboot_org';
@@ -20,11 +24,26 @@
$max_image_size = 512*4096;
%dev_tbl=(
-'/dev/hda1' => '0x301',
-'/dev/hda2' => '0x302',
-'/dev/hda3' => '0x303',
-'/dev/hda4' => '0x304',
-'Not defined' => '0x000',
+ '/dev/hda' => 0x0300,
+ '/dev/hdb' => 0x0340,
+ #'/dev/hdc' => 0x1200,
+ #'/dev/hdd' => 0x1240,
+ #'/dev/hde' => 0x3100,
+ #'/dev/hdf' => 0x3140,
+ #'/dev/hdg' => 0x3200,
+ #'/dev/hdh' => 0x3240,
+ #'/dev/hdi' => 0x3800,
+ #'/dev/hdj' => 0x3840,
+ #'/dev/hdk' => 0x3900,
+ #'/dev/hdl' => 0x3940,
+ #'/dev/hdm' => 0x5800,
+ #'/dev/hdn' => 0x5840,
+ #'/dev/hdo' => 0x5900,
+ #'/dev/hdp' => 0x5940,
+ #'/dev/hdq' => 0x5a00,
+ #'/dev/hdr' => 0x5a40,
+ #'/dev/hds' => 0x5b00,
+ #'/dev/hdt' => 0x5b40,
);
#-------------- device driver check ---------------
@@ -136,9 +155,9 @@
close(CONF);
# root_dev check
- $root_dev=$dev_tbl{$root};
+ $root_dev=&dev2rdev($root);
if($root_dev eq ''){
- print "root = $root not suppurt !!\n";
+ print "root = $root not supported !!\n";
exit;
}
@@ -166,6 +185,38 @@
return 0;
}
+sub dev2rdev{
+ my ($dev_file) = @_;
+ my $minor = 0;
+ my $rdev;
+
+ if($dev_file =~ s/(\d+)$//){
+ $minor = $1;
+ }
+ if(defined($dev_tbl{$dev_file})){
+ if($minor && $minor < 0x40){
+ $rdev = sprintf("%04x", $dev_tbl{$dev_file}+$minor);
+ }
+ }
+ return $rdev;
+}
+
+sub rdev2dev{
+ my ($devno) = @_;
+ my ($base, $offset) = (($devno & 0xff40), ($devno & 0x3f));
+ my $dev = "Unknown";
+ my $rdev;
+ unless($devno & 0x80){
+ foreach $rdev (keys %dev_tbl){
+ if ($dev_tbl{$rdev} == $base){
+ $dev = sprintf("%s%u", $rdev, $devno - $base);
+ last;
+ }
+ }
+ }
+ return $dev;
+}
+
sub switch(){
if($driver_installed == 1){
open(DEV,"+>$dev_file") || die "Can't open $dev_file. $!\n";
@@ -227,11 +278,7 @@
($append) =/^.*\"(.*)\".*$/;
}
- foreach $i (sort keys %dev_tbl){
- if(hex($dev_tbl{$i}) == hex($param[2])){
- $root = $i;
- }
- }
+ $root = &rdev2dev(hex($param[2]));
if(hex($param[0]) == 1){
$readonly_='read-only';
Counter: 11523,
today: 1,
yesterday: 0
|