*BOOT loader LanDisk [#rd810bf5]
&color(red){''uClibcベースで再構築、仕様を中変更しました。'' (2007/06/02) };~
-''BOOT loader LanDisk'' (BOOT LoaDer landiskの略かも) (^^;~
大まかに言えば、lilo(boot.b-selk)の変わりになるセレクタ機能付きboot loaderを、linuxのkexec機能を使って実装しようという試みです。~
~
同じようなことを考える人はたくさんいるようで、ぐぐるとkbootなるものが PS3Linux で実際に活用されているというでは・・・。ただし、コンソールがあってキー入力できることが前提なので、LANDISKで使用するのは、ちと厳しそうです。~
~
そこで、lilo(boot.b-selk)の思想を受け継ぐべく、LANDISKの限られたI/O機能(ボタンとLED)を駆使してセレクタ機能を実現するブートローダを作ってみようかと。~
~
なお、大まかな枠組みは「カーネルとユーザランドの統合単一イメージ:[[vmlinuz-initramfs-landisk]]」にて、大体完成しているので、ここでは、ブートセレクタ部と、ローダ部の作成(説明)を行うことにします。~
~
**ブートセレクタの仕様 [#rcd5ffc4]
-機能仕様
--ブートセレクトの数は4個(ユーザが使えるラベルは3個で、残り1個はレスキュー用)あれば十分かな?
--電源スイッチのトグル(ON/OFF)回数でブートラベルを指定。
--現在のブートラベルは&color(red){''赤LED''};の点滅パターンを見ればわかるようにしたい。
--6秒間、スイッチがトグルしなかった場合、現時点のブートラベルでもってブート開始。

--LEDの仕様
---ブートラベル1…LED点滅
---ブートラベル2…LED2回点滅→休止→LED2回点滅→休止→繰り返し
---ブートラベル3…LED3回点滅→休止→LED3回点滅→休止→繰り返し
---ブートラベル0…LED常時点灯(レスキュー用途)

--スイッチの仕様
---初期状態はブートラベル1。
---トグル動作が行われる毎に、ブートラベル2→ブートラベル3→ブートラベル0→ブートラベル1→繰り返し
~
~
**ローダ部の仕様 [#l62c6223]
-カーネルとブートパラメータの指定方法~
--/boot/bootld.confへカーネルブート情報($IMAGEと$APPEND)をユーザが定義するシンプルな仕様とする。~
具体的には、set_bootlabel()とset_network()関数をユーザが定義する(詳細後述)。~
なお、set_network()はレスキューモードで使用されるネットワーク設定関数である。~
--/boot/bootld.conf の格納場所~
ファイルシステムタイプがext2,ext3,vfat,reiserfsのいずれかの任意のパーティションに格納可能。~
複数のパーティションに /boot/bootld.conf が存在する場合はデバイス番号が大きい方を優先する。~
『例えば、万が一、内蔵ディスク(/dev/sda3)のbootld.conf を書き損じて起動しなくなった場合でも、USBスティック(/dev/sdb1)内の/boot/bootld.conf が優先されるので、USBスティックを差して起動すればシステムを復旧可能。』てな使い方を想定~
~
-set_bootlabel()~
引数は1個。
1,2,3のいずれかのブートラベル番号が引数として渡ってくるので、それに応じて、$IMAGEと$APPENDをセットして返す。
--''$IMAGE''~
パーティション指定部とカーネルイメージの場所をコロン":"で結合した形式とする。~
---''$IMAGE=/dev/sda1:/boot/vmlinuz-2.6.33-rc2-landisk''~
/dev/sda1の/boot/vmlinuz-2.6.33-rc2-landiskを使用するという意味。わかりやすいw~
bootld上では、全てのデバイスはSCSIデバイスとして扱われるため、IDE上のデバイス番号と異なる点に注意。/dev/hda1→/dev/sda1へと置き換えて記述すること。~
---''$IMAGE=/dev/sda1''~
イメージの場所は省略可能。この場合、/zImage、/vmlinuz、/boot/zImage /boot/vmlinuz の順にサーチする。
カーネルの実態へリンクを張っておくと便利かも。~
---%%''$IMAGE=""''%%~
イメージが無指定の場合、sdd→sdc→sdb→sdaの順にサーチする?←けっこう面倒かも。やらない。~
---%%パーティション指定部が未検出のデバイスだった場合%% ← 本処理は不要になった~
%%恐らくそれはusb_storageなので、自動的にusb_storageモジュールを組み込む。%%~
(''fdisk -l /dev/sdb''等とやれば、未検出のデバイスが検出されるようだ。)~
---''$IMAGE="http://192.168.1.80/zImage"''~
パーティション指定部が"http"であった場合、カーネルをwgetする。クロスビルド環境で開発している場合、けっこう便利かも。~
~
--''$APPEND''~
カーネルの起動パラメータ。/proc/cmdline。kexecの--append=引数そのもの。~
~
--set_bootlabel()の例~
#pre{{
set_bootlabel()
{
    case "$1" in
        1 ) # search for /zImage /vmlinuz /boot/zImage /boot/vmlinuz
            IMAGE=/dev/sda3
            APPEND="mem=64M console=ttySC1,9600 root=/dev/sda3"
            ;;
        2 ) # LANDISK original 2.4.21 kernel
            IMAGE=/dev/sda1
            APPEND="mem=64M console=ttySC1,9600 root=/dev/hda1"
            ;;
        3 ) # from usb-storage
            IMAGE=/dev/sdb1
            APPEND="mem=64M console=ttySC1,9600 root=/dev/sdb1"
            ;;
        sample1 ) # full path
            IMAGE=/dev/sda3:/boot/vmlinuz-2.6.22-rc2-landisk
            APPEND="mem=64M console=ttySC1,9600 root=/dev/sda3"
            ;;
        sample2 ) # from Network
            IMAGE=http://192.168.1.80/zImage  
            APPEND="mem=64M console=ttySC1,9600 root=/dev/sda3"
            ;;
    esac
}
}}
-set_network関数~
説明省略。例をみてくだい。~
--/boot/bootld.confのset_network()の例 … dhcpによるIPアドレス自動割当~
#pre{{
set_network()
{
    hostname bootld
    ifup -a
}
}}
--/boot/bootld.confのset_network()の例 … 固定IPアドレス~
#pre{{
set_network()
{
    hostname bootld
    
    # over write /etc/network/interfaces
    cat <<EOF > /etc/network/interfaces
auto lo
iface lo inet loopback
 
auto eth0
iface eth0 inet static
address 192.168.1.80
netmask 255.255.255.0
gateway 192.168.1.1
EOF

    # over write /etc/resolv.conf
    cat <<EOF > /etc/resolv.conf
nameserver 192.168.1.1
EOF

    ifup -a
}
}}
**実装 [#a1d0c5ed]
-/etc/init.d/bootld
--第1段階 … ブートセレクタ~
---選択されたブートラベルを$LABEL変数へセットする。~
---`select_btn $SELECT_DELAY `にて $SELECT_DELAY秒間の無入力期間を過ぎれば抜ける。~
--
#pre{{
#!/bin/sh

export PATH=/sbin:/bin:/usr/bin
/bin/mount -a

&color(green){echo ; echo "BOOT loader LanDisk V1.3"};
#----------------------------------------------
# 1. boot select
#----------------------------------------------
LABEL=0
BTN=push-switch.0
SELECT_DELAY=6

while [ "$BTN" != "" ] ; do
    LABEL=`expr \( $LABEL + 1 \) % 4`
    &color(green){echo "Select Boot Label $LABEL"};
    case "$LABEL" in
        0 ) ledctrl pwr=0 status=1 ;;
        1 ) ledctrl pwr=0 status=10R,200 ;;
        2 ) ledctrl pwr=0 status=10100000R,150 ;;
        3 ) ledctrl pwr=0 status=1010100000R,150 ;;
    esac
    BTN=`select_btn $SELECT_DELAY`
done
}}
--第2段階 … /boot/bootld.confの探索
---fdisk -l で接続中のデバイスを捜査し、逆順で(デバイス番号の大きい方から)サーチ。
---/boot/bootld.confが見つかれば、上書き。 
--
#pre{{
#----------------------------------------------
# 2. search /boot/bootld.conf
#----------------------------------------------
. /boot/bootld.conf

DEVLIST=$(&color(orange){fdisk -l /dev/sd?}; | awk '$1 ~ /^\/dev/ {print $1}' | sort -r )
for CDEV in $DEVLIST ; do
    mount -r $CDEV /mnt || continue
    if [ -r /mnt/boot/bootld.conf ] ; then
        &color(green){echo "/boot/bootld.conf found in $CDEV"};
        . /mnt/boot/bootld.conf
        umount -l /mnt
        break
    fi
    umount -l /mnt
done

}}
--第3段階 … カーネルの探索およびロード
---set_bootlabel を実行して ユーザが/boot/bootld.confで定義した$IMAGEと$APPENDを得る。
---$IMAGEをデバイス名$DEVとファイル名$KERNELに分解。~
---$DEVが'http'であれば、カーネルを /tmp/zImage.tmp として wget。~
---$DEVが'/dev/sd*'であれば、カーネルを /tmp/zImage.tmp としてコピー。~
コピーする際、カーネル名が未定義であれば、/zImage /vmlinuz /boot/zImage /boot/vmlinuz の順にサーチしてコピー。~
---レスキューモードが選択された場合は$DEVが未定義となるため、なにもせずにそのまま抜ける。~
--
#pre{{
#----------------------------------------------
# 3. search and copy kernel 
#----------------------------------------------
[ "$LABEL" != "0" ] && &color(blue){set_bootlabel $LABEL};

IMAGE_="$IMAGE:"
KERNEL=$(echo $IMAGE_ | cut -d: -f2)
DEV=$(echo $IMAGE_    | cut -d: -f1)
rm -rf /tmp/zImage.tmp

case $DEV in
    http )
        &color(green){echo "setup Network"};
        &color(blue){set_network};
        NETWORK=ON
        &color(red){wget $IMAGE -O /tmp/zImage.tmp}; 
        ;;
    /dev/sd* )
        mkdir /mnt2
        mount -r $DEV /mnt2 || break
        if [ "$KERNEL" = "" ] ; then
            for SIMG in /zImage /vmlinuz /boot/zImage /boot/vmlinuz ; do
                if [ -e "/mnt2$SIMG" ] ; then
                    KERNEL=$SIMG
                    break
                fi
            done
        fi
        &color(red){cp /mnt2$KERNEL /tmp/zImage.tmp};
        umount -l /mnt2
        ;;
esac
}}
--最終段階 … kexec
---カーネル(/tmp/zImage.tmp)があればkexec。
---なければレスキューモードに抜ける。
--
#pre{{
#----------------------------------------------
# 4. do kexec
#----------------------------------------------
if [ -e /tmp/zImage.tmp ] ; then
    &color(green){echo "Start Booting from Label $LABEL ..."};
    &color(green){echo "IMAGE=$DEV:$KERNEL"};
    &color(green){echo "APPEND=\"$APPEND\""};
    /bin/umount -a 
    &color(red){exec /sbin/kexec -f --append="$APPEND" /tmp/zImage.tmp};
else 
    &color(green){echo "Start Booting from Rescue mode ..."};
    
    # Network 
    [ "$NETWORK" = "" ] && &color(blue){set_network};

    # Daemon
    inetd
    btnctrl /etc/btn_action.conf &
    ledctrl pwr=0 status=1 buzzer=10
fi
exit 0
}}
-補足~
--&color(orange){fdisk -l /dev/sd?};~
USBストレージデバイスが認識されたり、されなかったり、状態が不安定で困っていたのですが、fdiskでパーティション情報をリストすることで、問題が一気に解決しました。~
どうやら、fdiskは、未認識のデバイス(scsi、usb-strage)を初期化する?効果があるようです。~
ただし、本来のやり方と違うと思うので、正当なやり方をご存知の方は、ぜひ、教えてください。m(_ _)m~
~
--$CDEV~
Current Deviceの略で/boot/bootld.confを読み込んだデバイス名、/dev/sdb1 等がセットされる。~
デバイス番号が実行時に確定するようなデバイス(例えばリムバーブルメディア)内に/boot/bootld.confを置き、かつそのデバイス内のカーネルやルートファイルシステムを読み出す場合に、set_bootlabelの記述に本変数を使うと幸せになれるかも。
#pre{{
	    IMAGE=$CDEV:/vmlinuz
	    APPEND="mem=64M console=ttySC1,9600 root=$CDEV"
}}
*インストール方法 [#ldcbbe9c]
-ファイル一式~
[[bootld-20070617.tgz:http://eggplant.ddo.jp/www/download/kernel26/bootld/bootld-20070617.tgz]]~
&color(red){失敗しても泣かない方のみ、ダウンロードしてお試しください。無保証です。};~
~
-/dev/sda1(/dev/hda1)へインストールを行う~
&color(red){/dev/sda};を自分の環境にあわせて読み替えること。~
例えば、PC-Linuxを使ってインストールする場合は、そのディスクが割り当てられたデバイスを正しく把握して読み替えること。~
#pre{{
# mount &color(red){/dev/sda1}; /mnt
# tar vxfz bootld-20070617.tgz -C /mnt
./boot
./boot/bootld.conf
./boot/bootld.dont_touch
./boot/bootld.dont_touch/lilo
./boot/bootld.dont_touch/boot.b-selk
./boot/bootld.dont_touch/lilo.conf
./boot/bootld.dont_touch/vmlinuz-initramfs-landisk.08
./boot/bootld.dont_touch/lilo.x86
}}
-liloでbootldを起動
--/mnt/bootld.dont_touch/lilo.conf の編集~
---timeoutを0にする。~
---&color(red){/dev/sda};を各自の環境に合わせてよみかえること。~
---bootld/dont_touchの実体がdiskで指定したデバイス内に存在することを確認すること。~
#pre{{
linear
boot=&color(red){/dev/sda};
disk=&color(red){/dev/sda};
bios=0x80
&color(red){timeout=0};
install=&color(red){/boot/bootld.dont_touch/boot.b-selk};
map=&color(red){/boot/bootld.dont_touch/map};
default=bootld
image=&color(red){/boot/bootld.dont_touch/vmlinuz-initramfs-landisk.08};
        label=bootld
        read-only
        append="mem=64M &color(red){usb-storage.delay_use=0}; bootld=/etc/init.d/bootld"
}}
&color(red){usb-storage.delay_use=0}; : USBストレージを即座に認識させるためのオマジナイ。~
--lilo
#pre{{
# /mnt/boot/bootld.dont_touch/lilo -r /mnt -C /boot/bootld.dont_touch/lilo.conf
Added bootld *
}}

-補足事項
--PC-Linux上からはlilo.x86を使うと良いかも。ただし当方ではテストしていません。~
--liloの書き込みはこの一回のみで金輪際不要です。lilo無しでも自在にカーネルを変更可能です。~
--dont_touchディレクトリは読んで字のごとく、一切触らないことを推奨します。~
--個人メモ:lilo打ち込み方法、別の方法(-r オプションなし)
#pre{{
linear
boot=/dev/sda
disk=/dev/sda
bios=0x80
timeout=0
install=&color(red){/mnt};/boot/bootld.dont_touch/boot.b-selk
map=&color(red){/mnt};/boot/bootld.dont_touch/map
default=bootld
image=&color(red){/mnt};/boot/bootld.dont_touch/vmlinuz-initramfs-landisk.08
        label=bootld
        read-only
        append="mem=64M usb-storage.delay_use=0 bootld=/etc/init.d/bootld"
}}
~
#pre{{
# /mnt/boot/bootld.dont_touch/lilo -C &color(red){/mnt};/boot/bootld.dont_touch/lilo.conf
}}
**インストール方法 … &color(red){''裏技版 -- bootld.mbr''}; [#md0ceeb8]
-(PC-)LINUXに中身が消去されても良いHDDを接続します。~
USBストレージ経由で接続したHDDが、PC-Linux上で/dev/sdbと認識されたと仮定します。~
~
-bootld.mbr~
[[bootld_255h_63s.mbr.gz:http://eggplant.ddo.jp/www/download/kernel26/bootld/bootld_255h_63s.mbr.gz]]をダウンロードして、ターゲットディスクにddします。~
bootldを含む約8MBのファーストパーティションが作成されます。~
&color(red){''注意:MBRごと上書きしますので、ディスク上の元のデータは全て消えてなくなります(吸い出せなくなります)。''}; 
#pre{{
# gzip -d bootld_255h_63s.mbr.gz
# dd if=bootld_255h_63s.mbr of=/dev/sdb
# sync;sync;sync
}}
以上で終了です。~
~
-確認~
fdisk、または、マウントして中身を確認することができます。~
なお、リブートするなどしてUSBストレージを再認識させる必要があるかもしれません。~
(MBR毎強制書き換えを行ったため、OS内に保持されたdiskstat(情報)の一貫性が損なわれているかもしれませんので)
#pre{{
# fdisk -l /dev/sdb
Disk /dev/sdb: 40.9 GB, 40982151168 bytes
255 heads, 63 sectors/track, 4982 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1               1           1        8001   83  Linux
}}
-補足事項--作り方
--USBスティック内にfdiskで8MBのパーティションを作成。
--その中に、bootld関連ファイルをコピーして、liloを打ち込む。
--dd でMBRとパーティション毎吸い出して、bootld.mbrとする。
--古いHDDにddで書き戻して、LANDISKに組み込み、起動することを確認した。
~
-
&color(red){''2.6最新カーネルを使って、LANDISKの2.4ベースオリジナルシステムをブートするこの矛盾……''};~
~
*comment [#dab29d4d]
#vote(動いた[5],動かなかった[0],動かなかったに投票したけど、なんとかして動かした[0],bootld.mbrを試した。起動成功[3],bootld.mbrを試した。起動失敗[0]);
#vote(動いた[6],動かなかった[0],動かなかったに投票したけど、なんとかして動かした[0],bootld.mbrを試した。起動成功[3],bootld.mbrを試した。起動失敗[0]);

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