98/V のドライバ作成のための資料

以下の文章は,私が個人的に調べたもので公式のものではありません. したがって,間違っている可能性があります.

1. モード

マニュアル等にも書いてあるように,98/Vは仮想86モードを利用しています. 仮想86モードは,ブート時のMS-DOS環境を引き継いだAT互換モードと98アプリケーション が動作する98モードの2つのモードがあります.また,エミュレーションを行う プロテクトモードがあります. これらのモードを推移していくわけです. 98モードでI/O操作を行うとフォルトが起こり,プロテクトモードに移行しそこで 98のI/Oエミュレーションをするわけです. また,CDBRIDGEなどはAT互換モードに,AT用の デバイスドライバーを置き,その入力と出力をプロテクトモードをかいして, 98モードへ橋渡ししています.


2. デバイスドライバの書式

デバイスドライバは,MS-DOSのEXEファイル形式となっています. ファイルの拡張子は"NED"にするのがきまりのようです.登録の仕方は emulator.infの[LOAD]セクションに"DEVICE=*****.NED"のように 追加します."DEVICE"の他に"DRIVER"等もありますがどう異なるのかはわかりません. 当然プロテクトモードで動きます.

全体の構成は次のようになります.


code    segment use16

        assume  cs:code, ds:data

;ヘッダ部

        db      '86FMPCMI'      ;8バイトの名前(ASCII),どう利用されるかは不明,

                                ;重ならなければいい?

        dw      code,00bah      ;コード用に00bahのセレクタを使用しているらしい.

                                ;このcodeの値を使いアロケーションされる.

        dw      data,00b2h      ;データ用で同上

        dw      0002h           ;セグメントの数?

start:  ;LOADされたときの実行ポイント

;コードセグメント

        pushad

        ...

        popad

        ends



data    segment

;データセグメント

        ...

        ends

        

        end     start


3. コールゲート

98/Vのカーネル機能の呼び出しは,0010h:0000hのコールゲートを呼び出すことで 行います.呼び出し時のAXレジスタの値で処理が変わります. すべての機能は調べてませんが,わかっているものについて列挙します.

C1AX=0003h
機能 仮想86モード(AT互換モード)のコンベンショナルメモリの
フリーエリアの獲得
入力cx=獲得したいバイト数
返値エラー時 キャリーフラグ=1
ax=割り当てられた領域をプロテクトモードでのアクセスするためのセレクタ
dx=割り当てられた領域の仮想86モードでのセグメント

C2AX=0010h
機能各モジュールとのインターフェース(後述)
入力dx:esi=パラメータブロックへのポインタ

C3 AX=0020h
機能 仮想86モード(AT互換モード)の全メモリ空間の アクセスのためのセレクタと
レジスタの状態が保存されている領域のセレクタの獲得
返値エラー時 キャリーフラグ=1
ax=メモリーのセレクタ
dx=レジスタのセレクタ
備考xx番地をアクセスしたいメモリの86モードでの リニアアドレスとすると
プロテクトモードではax:xxでアクセスできる.ただし書き込み不可.
dx:xxを操作することでxx番地にあたるレジスタの値を操作できる
レジスタの保存状態は下の通り

レジスタの保存状態
オフセットレジスタ
+00hedi
+04hesi
+08hebp
+10hebx
+14hedx
+18hecx
+1cheax
+24heip
+28hcs
+2cheflags
+30hesp
+34hss
+38hes
+3chds
+40hfs
+44hgs

C4AX=0021h
機能 仮想86モード(AT互換モード)でのサブルーチンの呼び出し
備考 事前にC3を使って86モード時のcs,ipレジスタを呼び出したいアドレスに
設定しておくことが必要

C5AX=0022h
機能 仮想86モード(AT互換モード)での INT xxhの実行
入力dl=実行したい割り込み番号
備考 例えばdl=21hでDOSのファンクションコールが実行される.このとき
事前に C3を使って仮想86モード時のレジスタを設定しておくことが必要

C6AX=0030h
機能 仮想86モード(98互換モード)の全メモリ空間のアクセスのための セレクタと
レジスタの状態が保存されている領域のセレクタの獲得
返値エラー時 キャリーフラグ=1
ax=メモリーのセレクタ
dx=レジスタのセレクタ
備考 xxをアクセスしたいメモリの86モードでのリニアアドレスとすると
プロテクトモードではax:xxでアクセスできる.こちらは書き込みも可.

C7AX=0041h
機能 エラーメッセージ出力後98/V停止
入力 dx:edi=エラーメッセージ文字列(ASCIIZ)アドレス


4. ディスパッチ

98/Vでは,割り込み信号やフォルトなどのすべての割り込みは"Dispatcher" と呼ばれているものが処理します.割り込み発生時にどのルーチンに制御を 移して欲しいかをC2を使い登録しておきます.

以下にC2で指定するデータの書式を示します. (W)はこちらで書き込む,(R)は値が返ってくるもの.

オフセット説明
+0BYTE(8)'DISPATCH'(W)ASCII名,固定
+8WORD0000h(R)返値,0以外でエラー発生
+aBYTEnum(W)登録数
+bWORD00h不明
...以下個々の登録を複数列挙
BYTE0ffh(W)終端を意味する

個々の登録の書式は先頭の1バイトで決まる.書式は以下の通り.

オフセット説明
+0BYTE00h(W)I/Oフォルト時
+1WORDaddr(W)アクセスしたIOポートアドレス(98モードでの)
+3WORD0000h不明
+5BYTE00h不明
+6WORDoffset(W)フォルト発生時の処理ルーチンのアドレスのオフセット部
+8WORDcode(W)同セレクタ

オフセット説明
+0BYTE03h(W)ハードによる割り込み時
+1BYTEirg(W)対応する割り込みベクトル *1
+2WORD_86int(W)割り込み発生時の処理ルーチンのアドレスのオフセット部
+4WORDcode(W)同セレクタ
*1 起動時のATモードで標準でPICに設定されている値を使う.
98/V使用時は設定は変更されているが内部で変換される.

オフセット説明
+0BYTE04h(W)仮想86モードでの halt命令による停止時
+1BYTE(8)'ASPIBRIG'(W)ASCII名,停止個所の識別に使う
+9WORDaspib(W)停止時の処理ルーチンのアドレスのオフセット部
+bWORDcode(W)同セレクタ

オフセット説明
+0BYTE05h(W)他のモジュールからの C2による呼び出し時
+1BYTE(8)'TIMER '(W)ASCII名,呼び出しの識別に使う
+9WORDl05D0(W)呼び出し処理ルーチンのアドレスのオフセット部
+bWORDcode(W)同セレクタ


5. ディスパッチ時の処理ルーチン

Dispatcherに呼ばれた後の処理について述べる. 呼ばれたときに,各種の状態がスタックに置かれている.この情報を使い 各種の操作を行う.逆に処理から戻るときには,スタックの値を設定して返る.

5.1 I/Oフォルト時

98モードではすべてのIO操作でフォルトが発生する. スタック状態は次の通り.(上の桁から76543210と各ビットを呼ぶことにする)

オフセット説明
sp+1chBYTE(W)単入力時は入力された値を設定
sp+25hBYTE(R)フォルト時のIO操作の種類
第2ビット=0 入力; 1 出力
第3ビット=0 ブロック転送時アドレス増加; 1 アドレス減少
第4ビット=0 単入出力; 1 ブロック転送
sp+28hBYTE(R)単出力時は出力する値
sp+28hDWORD(R)ブロック転送時は転送元(先)オフセット
sp+2chWORD(R)転送元(先)セレクタ
sp+2ehDWORD(R)ブロック転送時の転送バイト数
これらを使い入出力のエミュレーションをする.

5.2 ハードによる割り込み時

6.1参照

Dispatcherに登録していない外部信号による割り込みに関しては, AT互換モードでリアルモード割込み動作のエミュレーションが行われる.

5.3 仮想86モードでのhalt命令による停止時

仮想86モードからプロテクトモードへの移行に利用できる. 98モードで次のようなコードを実行すると移行できる.


        hlt

dp1     dw      dp2 - dp1       ;haltの次に識別名への相対値を置く

        ret

dp2     db      'ASPIBRIG'      ;8バイトの識別名(ASCII)

                                ;この名前のルーチンが実行される.

5.4 他のモジュールからの呼び出し時

C2により呼ばれ,他のモジュールへのサービスを提供する. スタック状態は次の通り.

オフセット説明
sp+26hDWORD C2使用時のパラメータブロックポインタのオフセット 6節
sp+2ahWORD同セレクタ部


6. 他のドライバで提供されている機能

6.1 仮想86モードでの割り込み

次の書式でC2を使い98モードでの割り込み許可を行う.

オフセット説明
+00hBYTE(8)'PIC_FUNC'(W)ASCII,モジュール名,固定
+08hWORD0000h(R)返値,0以外でエラー発生
+0ahWORD0000h(W)機能選択番号 0以外については不明
+0chBYTEirg(W)使用許可する割り込みベクトル(98モードでの)
+0dhWORD0000h (R)98モードでの割り込みを発生させるための
ルーチンのアドレスのオフセットがセットされる
+0fhWORD0000h(R)同セレクタ部

割り込み発生のエミュレーションは alレジスタに98モードでの割り込みベクトルを 設定し上の+0dh,+0fhにセットされた番地をfar callする.これにより,98モード復帰時に リアルモードでの割り込み動作が行われる.

6.2 タイマー

ハードウエアタイマーを使ったタイマーが用意されている. C2を使い設定する. 初期値から1msec毎にカウントダウンし0で指定のサブルーチンが呼ばれる.

オフセット説明
+00hBYTE(8)'TIMER '(W)ASCII,モジュール名,固定
+08hWORD0000h(R)返値,0以外でエラー発生
+0ahWORDtkind (W)タイマーの種類 値が0のとき1回で終了
1のとき自動的にカウンタが更新され連続動作
+0chWORDcount(W)カウンタ初期値 msec単位
+0ehWORDcprog (W)カウンタが0となったときに呼ばれる
ルーチンのアドレスのオフセット部
+10hWORDcode(W)同セレクタ部


7 ソースサンプル

サンプル


TOPへ戻る