extipl::Develop.txt for FreeBSD/Linux

                           April 5 1999

                        takamiti@tsden.org
                         extipl@tsden.org
                http://www.tsden.org/takamiti/extipl/

==============================================================================
1. はじめに
  1.1  IPL Code の作成方法
2  extipl の compile
  2.1  FreeBSD 環境
  2.2  Linux 環境
3. サンプルソースについて
4. 技術情報
  4.1  動作時のメモリマップ
  4.2  動作解説
  4.3  任意のハードディスクからブートさせる仕掛け
==============================================================================


[1] はじめに

このドキュメントは、extipl に物足りなさを感じたとか、自分の手で IPL を書いて
みたい人達のために用意したものです。しかし、この IPL の開発はコードサイズの制
限や、些細なチョンボが大きな不幸の入口になるなど、誰でもが手軽に使えるものでは
ありません。腕に自信があり、どんなことが起こっても慌てずに対処できる人だけが、
自分の責任でお試しください。
そんなわけで、このドキュメントは extipl package のソースコードを苦もなく読める
人を対象に書いています。

もし、ここのヒントからより賢い master-IPL ができたならば takamiti@tsden.org
あるいは extipl@tsden.org までお知らせいただければうれしいです。


[1.1] IPL Code の作成方法

次のような手順で独自の master IPL を作ることができます。なお、作業ディレクトリ
は extipl/samples/ として説明します。

  (1) サブディレクトリ samples に添付されているサンプルソースと、「[4] 技術情
      報」とを参考にしてあなた独自の IPL ソースを作成し、それを myipl.asm と
      して保存したとします。

  (2) 添付されている samples/Makefile に

        myipl.bin : myipl.asm

      の１行を書き加えてから、

        $ make myipl.bin

      とします。make が無事に終了すると myipl.bin というものができています。
      これが、目的の手作り IPL のバイナリです。アセンブルリストが myipl.lst
      として同時に出力されますから、必要ならばコード内容の検証に使えます。

  (3) 出来上がった myipl.bin の内容が正しいかどうかをきちんと確認してください。
      この作業で手を抜くと後で泣くことになります。実際に extipl によって書き込
      まれる内容を知りたければ、デバッグオプションを使います。

        $ extipl -d install wd0 myipl.bin

      とすることにより、extipl がブートセクタに書き込むイメージそのものを
      "./_BootSec.?????" として取り出す事ができ、より現実的な点検が可能です。
      ("?????" の部分には書き込む対象のセクタアドレスが使われます)

  (4) これらのテストで問題がなければ、

        # extipl install wd0 myipl.bin

      とすることによりハードディスクのブートセクタに新しい IPL を書き込むこと
      ができます。もちろん、フロッピーディスクからブートし、ハードディスクか
      らのブートをシミュレートできるように IPL-Launcher を組み込んでいるなら
      ば

        # extipl fdtest fd0 myipl.bin

      とすることができます。なお、extipl は サブコマンド install で書き込む時、
      対象プログラムの先頭から 446 バイトを超える部分を強制的に切り捨てます。
      あくまでも許されるプログラムの長さは 446 バイト以下であることを忘れない
      でください。もし、読み込んだ myipl.bin の大きさが 446 バイト以下ならば、
      その分だけをブートセクタに書き込みます。

         install や fdtest コマンドが続く引数を解釈できることは extipl.txt に
         明記していません。ソースコードを読むと何か良いことがあるものです。


[2] extIPL の compile
この extipl package は FreeBSD 2.2.8R, 3.1R と Linux 2.0.36 でコンパイルできる
ことを確認しています。
両環境とも、あらかじめ nasm を http://www.web-sites.co.uk/nasm/ から入手して使
えるようにしておかなければなりません。


[2.1] FreeBSD 環境
サブディレクトリ src に移動して、make としてください。もし、make が失敗するなら
ば Gnu-make で試すか、Makefile を適宜書き換えてください。

[2.2] Linux 環境
サブディレクトリ src に移動して、make としてください。ドキュメント類のインスト
ール先を変更したいときには、Makefile を直接書き換えるか

    # PREFIX=yourPrefix DOCPATH=yourDocPath make install

としてください。


[3] サンプルソースについて
サンプルとして、DISK BIOS の拡張サービスを利用し、LBA アクセスにも対応させた以
下のソースコードを添付します。

    lba_xipl.asm : LBA/CHS 両用 Extednde IPL ソース
    lbafdsim.asm : LBA/CHS 両用 Extednde IPL のフロッピーテスト版
    lba_main.asm : LBA/CHS 両用 Extednde IPL 本体

コードサイズ 446 バイトの制限があるために、アクティブ領域の変更機能を外してい
ます。また、コードサイズが増えていますので DR-DOS の password 機能と共存ができ
ません。エラー処理も甘くなっています。特に拡張領域内でのセクタアドレス計算ルー
チンは性善説にもとずいた手抜きをしていますので注意してください。もう少し、ロジ
ックを洗えば何とかなる .... かな？
この IPL を LBA 専用にすることは極めて容易ですし、その分コードサイズへの負荷も
軽くなりアドレス計算ルーチンをまともなものにできますが、LBA 非対応のＨＤが接続
された時に非常に困ったことになります。
LBA アクセス部分のみを抜き出して使う時には、使う環境に十分に注意してください。


[4] 技術情報

[4.1] 動作時のメモリマップ
Extended-IPLはハードディスクのブートセクタに置かれる master-IPL で、system ROM
の IPLルーチンにより 0x07C00 番地にロードされ制御が移されます。この 0x07C00 
番地は通常ディスクに書かれた IPL を読み込むために使われますので Extended-IPL 
は自分が起動させる OS のローダのためにこの領域を避け、自分自身を 0x0600 番地に
移動し本来の仕事を開始します。0x0600 番地で走る時のメモリマップは次のようになっ
ています。

        |                      |
        ^                      ^
        |----------------------|
        |                      |
        |     512 byte         | <- Extended-IPL が OS ローダを読み込む場所
        |                      |             （最初は自分もここに読まれる）
0x07C00 +======================+ <- Extended-IPL の stack 領域の上限
        |                      |             （起動時に sp にセットする値）
        ^                      ^
        |------------------55AA| <- boot 標識 0xAA55
0x007BE |______64_byte_________| <- partition table 作業領域
        |                      |
        |     446 byte         | <- Extended-IPL の code & data 領域
        |                      |
0x00600 +======================+
        |                      |
        ^                      ^
        |                      |
        |                      | <- このあたりはシステム予約の作業領域や
        |                      | <- 割り込みベクタテーブルがある。
0x00000 +----------------------+
/////////////////////////////////////////////////////////////////////////



[4.2] 動作解説
0x0600 に移動した Extended-IPL は次のような手順でアクティブ領域を探しそこから
ブートするか、あるいはユーザの領域選択を待って該当 OS をブートさせます。なお、
この説明は概念的なもので、実際のプログラムの動作とは厳密には違っています。

    (1) フロッピードライブのモータが off になるまでの間、シフトキーが押されるか
        どうかをチェックします。
                もし、シフトキーが押されたならば (3) に飛びます。

    (2) partition table からアクティブ領域を探します。
                もし、アクティブ領域があれば (4.5) に飛びます。
                しかし、アクティブ領域のブートセクタの内容が正規のブートプロ
                グラムと認められないときには警告のベルを鳴らして (3) に移り領
                域選択状態になります。

    (3) 該当ハードディスクのパーティションテーブルをダンプし、選択プロンプト
        "Boot #?:?.?" を出します。プロンプト に続く数字は HD ユニット番号とパ
        ーティションテーブルの階層、アクティブ領域の番号です。全領域非アクティ
        ブならば領域番号は原則として "1" となります。

    (4) キー入力を待ち、押されたキーを次の順序でチェックします。

        (4.1) 押されたキーが "0", "1"〜"4" ならば選択された番号を表示し、次の
              キー入力を待つために (4) に戻ります。

        (4.2) 押されたキーが <Enter>, <End> ならば(4.3)以降の処理を行いますが、
              これら確定キーに該当しなければ警告のベルを鳴らし (4) に戻ります。

        (4.3) 選択された番号が "0" ならば、BIOS から見える次のハードディスクの
              先頭セクタを 0x07C00 番地に読み、パーティションテーブルだけを
              0x07BE 番地にコピーし、(3) に戻ります。その際に各変数はそれぞれ
              の状態に合わせて再設定されます。

        (4.4) "1"〜"4" が選択されたが、該当する領域が使用されていなければ警告
              のベルを鳴らして (4) に戻ります。

        (4.5) 選択された領域が 拡張領域ならば、拡張領域内の先頭セクタを 0x07C00
              番地に読み、パーティションテーブルだけを 0x07BE 番地にコピーし、
              階層テーブル表示のプロンプトを更新して (3) に飛びます。

        (4.6) 該当領域の先頭セクタの内容（OS のブートローダ）を 0x7C00 番地に
              読み込みます。
                        | (2) からここに飛び込んだ場合には期待しているレジスタ
                        | の値が下記 (b),(c) には該当しませんので <Enter> キー
                        | が押された時と同様に処理されます。

          (a) 押されたキーが <Enter> ならば、、、
                0x7C00 に読み込まれたブートセクタの末尾の 0xAA55 を見て、正規ブ
                ートセクタであることを確認してから (5) に飛びます。
          (b) 押されたキーが <End> ならば、、、
                <Enter> キー同様に正規のブートセクタであることを確認します。そ
                してブート対象としているハードディスクドライブが 1 台目で基本領
                域の時に限り、選択された領域に active flag をセットしたものをマ
                スタブートセクタに書き戻してから (5) に飛びます。

    (5) 0x7C00 に jump することにより該当 OS のブートプログラムを起動させます。こ
        の時各レジスタ値は以下のような意味を持っています。
            ax, bx, cx, dh, di, bp = 無意味
	    dl = DISK BIOS から見たドライブ番号 (0x80, 0x81, ..)
            ds = Extended-IPL のデータセグメント値　(0x0000)
            si = 起動したローダの置かれた領域を示すポインタ
                 起動領域番号を n とすれば si の持つ値は次の式で表されます。

                     si = 0x07BE + 16 * (n - 1)
                                              (n は 1 .. 4 の値を取る)

                 これにより起動された OS のローダは ds:si の示す番地を手がかり
                 にして自分の置かれた領域の情報を取り出すことができます。
                 また、このときにポインタ ds:si の示す番地にはアクティブ領域で
                 あることを OS のローダに知らせるために MSB をセットします。
                 この ds:si の値は IBM の技術資料でも保証されています。


[4.3] 任意のハードディスクからブートさせる仕掛け

Extended-IPL は ROM BIOS を使い、上記のような手順で OS をブートしますが、もし
起動したい OS のローダさえ対応しているならば BIOS 経由で 2台目以降としてに認識
されるハードディスクからもブートさせることができます。ほとんどの OS は 1 台目
のハードディスクからしかブートできませんので過度の期待はしない方がよいかも知れ
ません。

ここでは、Extended-IPL が 2 台目以降のハードディスクから読み込んだことを OS の
ブートローダにしらせるからくりについて説明します。
まず、いまさらの事でしょうが、1つのパーティションを表す情報は次のような構造体と
等価です。

            typedef unsigned char byte;

            typedef struct {
                byte head;
                byte sector;
                byte cyl;
            } hd_addr;

            typedef struct {
                byte                bootind;        <<--- active flag
                hd_addr             start;
                byte                systemind;
                hd_addr             end;
                unsigned long       start_sector;
                unsigned long       nr_sectors;
            } partition;

ここで、ブート可能なパーティションであることを示す partition.bootind の内容は
通常 0x80（ブート可）あるいは 0x00（ブート不可）の2つの値しか持ちません。
Extended-IPL も 1 台目からブートしたときには選択された領域の partition.bootind
を 0x80 にセットして OS のローダに制御を渡します。しかし、2 台目から起動したな
らば、この値を 0x81 として読み込んだローダに制御を渡します。
つまり、Extended-IPL 経由で呼び出された OS のローダは partition.bootind の MSB
をマスクした値を見れば BIOS が認識しているハードディスクの何台目から自分が読ま
れたのかを知ることができます。
しかし、起動したハードディスクが IDE type なのか SCSI type なのかを知る事はで
きません。このあたりは OS のローダの仕事になります。

# end of develop.txt
