*はじめに [#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

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS