*はじめに [#fc80b841]
本ソフトウェアはKernelの切り替えを動的に行うプログラムです。~
~
最近、2.6カーネルが動き出したり、SH-Linuxのホームページにおいて、~
SH版 Fedora Core 2 互換パッケージ等が公開されてたりして、~
SH-Linux周辺に新たな動きがあります。~
~
それらを見て、私もカーネルを変更したくなりまして。。。~
しかし、LANDISKの箱を開けたくなかったのと、システムを壊してしまうのが嫌だったので、~
本プログラムの作成を思い立った次第です。~
なお、本ソフトウェアは、mipsマシンに実装されているakmemや~
2.6カーネルで実装されるといわれるkexec等の思想をそっくりそのまま頂きました。
*ソフトウェアの構成と動作概略 [#df70989c]
-''ソフトウェアの構成''~
本ソフトウェアは次の2つのパーツから構成されています。~
kernelsw.pl ・・・ フロントエンドスクリプト~
kernelsw.o ・・・ デバイスドライバモジュール~
~
-''動作概略''~
kernelsw.plは、kernelsw.oへ、Kernel起動パラメータとKernelイメージの転送を行うPerlスクリプトです。~
kernelsw.oは上記スクリプトから送られてくるパラメータとカーネルイメージを内部メモリに取り込み、~
Linux起動時の初期領域へ再配置して、新Kernelの起動を行うデバイスドライバです。~
~
kernelsw.plのもう一つの機能は、
シャットダウンシーケンスの最終段階で、kernelsw.oを起動して~
カーネルのスイッチを行う仕掛けを提供することです。~
すなわち、/sbin/rebootや/sbin/haltのラッパーとして動作する機能です。~
本機能により、rebootやhaltに偽装したkernelsw.plは、内部の状態に応じて、~
本来のhaltコマンドを起動してシャットダウンシーケンスを行う、~
あるいは、kernelsw.oを呼び出してカーネルのスイッチ動作を行う、~
等の処理を適切に選択して実行します。~
~
-''&color(red){Ver 2.1の追加オプション};''~
&color(red){追記:2005/06/11: 実は、kernelバージョンに係わらず本オプションは不要でした。};~
%%2.6系カーネル対応機能として、%%カーネルのロードアドレスを指定するオプションを追加しました。~
#pre{{
offset_address=0x00800000 等。
}}
本オプションを指定しない場合、カーネルイメージは、LinuxSHのデフォルトアドレス、~
0x00210000へロードされます。~
~
-''&color(red){Ver 3.2の追加オプション};''~
--カーネルサイズの制限を2MB->16MBへ拡張~
--NetBSDカーネルのブート機能を追加~
#pre{{
offset_address=0x00001000 ← 0x1000を指定するとNetBSDモードになる。
}}
--NetBSDカーネルと共にRAMDISKをルートデバイスとして起動する機能を追加~
#pre{{
miniroot=./ramdisk.img ← NetBSDモードでは、ルートデバイス用のRAMDISKを指定可能
}}
~
*インストール [#p6102f20]
-''リマウント''~
ルートファイルシステムを以下のコマンドで書き換え可能にします。
# mount -o rw,remount / # RWでリマウント
-''デバイスファイル/dev/kernelsw(c,52,0)の作成''~
本デバイスドライバモジュールはキャラクタ型デバイスとして実装されており、~
/dev/kernelsw(c,52,0)を経由して情報のやりとりを行います。~
~
次のコマンドで/dev/kernelsw(c,52,0)の作成を行います。~
# mknod /dev/kernelsw c 52 0 # デバイスファイルの作成
# chmod 600 /dev/kernelsw
-''kernelsw.oのコピー''~
/lib/module...下へmiscディレクトリを作ってその中へkernelsw.oコピーします。
# cd /lib/modules/2.4.21/kernel/drivers
# mkdir misc
# cp kernelsw.o /lib/modules/2.4.21/kernel/drivers/misc
-''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でリマウント
*コマンドオプション [#w8824649]
-''help''~
まずは、ヘルプです。
#pre{{
# 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もしくは未定義値になっています。~
#pre{{
# 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"オプションを指定します。~
通常は使用しないでください。~
なぜなら、本オプションを指定すると即座にスイッチ動作が開始されるため、~
実行中のプロセスは、&color(red){''電源が突然落ちたに等しい状態''};になるからです。~
万が一使用する場合は、実行中のプロセスを可能な限り停止させ、~
さらに、ファイルシステムを可能な限りアンマウント、もしくは、リードオンリーでリマウントした~
状態で使用してください。~
~
-''クリーンな状態への戻しかた''~
"-r"オプションを指定します。~
確保されたメモリエリアを開放すると共に、ドライバをアンロードします。~
~
-''制限事項''~
--カーネルサイズの上限は、2MB(2,097,152バイト)です。~
(Ver 3.2において、本制限は16MBまで拡張されました。)~
--SH4アーキテクチャのみ対応しています。(LANDISKアーキテクチャと言うべきかも)~
*Kernel Switcherの動作確認 [#ucfec785]
-''動作確認方法''~
それでは実際に、~
/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ファイルは次のようになります。~
#pre{{
linear
boot=/dev/hda
disk=/dev/hda
bios=0x80
timeout=50
default=linux
&color(red){image=/boot/zImage};
label=linux
&color(red){root=/dev/hda1};
&color(red){read-only};
&color(red){append="mem=63M console=ttySC1,9600"};
}}
※kernelsw.plは&color(red){赤文字};の部分だけを認識します。~
なお、マルチラベルには対応していないので、一つのラベルだけを記述するようにしてください。~
~
-''Kernel起動パラメータとKernelイメージの設定''~
準備したlilo.confファイルを指定して、kernlesw.plを実行します。
#pre{{
# 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''~
この状態で、&color(red){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
&color(red){正しく動作確認できたなら、電源スイッチをON側に戻しておきましょう。};~
~
-''もとのLANDISKの環境へ''~
電源スイッチをOFFにするとLANDISKはシャットダウン動作を開始して、
電源がOFFされます。~
再度電源をONすると、もとの64MBの状態に復帰します。~
~
-''次なる挑戦''~
本Kernelsw.plを用いてプレーンなdebian環境を/dev/hda3上に構築したいと考えています。~
~
*参考文献 [#lf315461]
-[[LinuxSH:http://linuxsh.sourceforge.net/docs.php3]]~
SH-IPL Sequence,LILO Sequence,LinuxSH Kernel Boot Sequence等、~
SH-Linuxの起動のシーケンスが非常に参考になりました。
-[[SH Linux TIPS:http://www.si-linux.com/labo/shlinux/]]~
デバイスドライバの書き方を参考にさせて頂きました。~
-[[LANDISK - mizore Wiki:http://www.mizore.jp/wiki/index.php?LANDISK]]~
唯一のデバッグ手段がLEDでしたので、その解析ネタが非常に参考になりました。~
-[[プロジェクトiohack:http://sourceforge.jp/projects/iohack/]]~
LANDISKのKernelを含むソースコード一式いただきました。~
-SH4のプログラミングマニュアル~
*人柱になっても良いという方へ [#scd63895]
非常に危険なプログラムですが、使ってみたいという方はどうぞ!~
次の場所へソースを含め、一式置いておきます。~
http://eggplant.ddo.jp/www/download/SH-Linux_Kernel_Switcher/
~
*個人メモ [#b62ce92a]
-''/dev/hda5等から起動するには?''~
--/dev/hda1〜4以外から起動させる場合は、下記吉藤さんのパッチが有効。
--他の方法として、apppendオプションで「root=/dev/hda5」等と明示的に指定する方法もある。
-
吉藤さんから頂いたパッチ~
#pre{{
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));
#pre{{
+ 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