XMS ドライバ

KusaReMKN

この記事に置いて HHHH:hhhh の表示はセグメント・オフセット方式のメモリアドレスを表す。 セグメント部は HHHH であり、オフセット部は hhhh である。 いずれも 16 進数で記述される。 また、リニアアドレスなどその他の 16 進数には、DEADBEEFH のように末尾に H を添えて表す。

そもそも XMS とは

XMS とは eXtended Memory Specification の略称であり、MS-DOS 上でメモリを扱う規格のひとつである。

そもそも、Intel 8086 CPU はセグメント方式によるメモリ管理の制約により、1 MB ほどの領域しか扱うことができなかった。 この領域には VRAM や BIOS のコードも配置されており、一般に利用可能なメモリ領域は 640 kB であった (この領域を コンベンショナルメモリ という)。 MS-DOS の本体や各種デバイスドライバ、更には FEP などをこの領域に配置していたのではメモリ不足でアプリケーションを実行できなくなってしまう。 そのため、コンベンショナルメモリ以外の領域にそれらを配置してやる必要があった。 XMS は i386 以降の CPU で利用可能な 1 MB 以降のメモリを扱うものである。

XMS は HMAEMBUMB の領域からなる。

HMA
High Memory Area の略称であり、0FFFF:0100 (100000H) から 0FFFF:0FFFF (10FFEFH) のメモリ領域を指す。
この領域はリアルモードでアクセス可能な 1 MiB 以上の領域である。 しかし、アドレスのセグメント部は 0FFFFH に固定であり、複数のプログラムでこの領域を利用するには都合が悪い。 通常は CONFIG.SYS に記述される DOS=HIGH の設定によって MS-DOS の本体が常駐する。
EMB
Extended Memory Block の略称であり、10FFF0H 以降のメモリ領域を指す。
XMS ドライバを利用してコンベンショナルメモリとの間でデータを転送し合うことができる。
UMB
Upper Memory Block の略称であり、0A0000H や 0C0000H から 0FFFFFH の VRAM や BIOS などが利用しているメモリ領域を指す。
この領域の未使用域を RAM として利用できる。 CONFIG.SYS に記述される DOS=HIGH,UMB の設定によって UMB を利用可能にすると、DEVICEHIGH コマンドや INSTALLHIGH コマンドによってデバイスドライバや常駐プログラムを UMB に組み込めるようになる。 COMMAND.COM の内部コマンド LOADHIGH (LH) を利用することでも UMB を利用できる。

利用開始手続き

まず MS-DOS のファンクションコール INT 2Fh を利用して XMS ドライバの有無とコール先を取得する。

XMS ドライバの機能を利用するには、ここで得られる値 XMS_CALL を CALL far する。

ソースコード

このサブルーチンは XMS ドライバをチェックし、成功すれば XMS_CALL にコール先をストアし、失敗すれば CF を立てる。

CHK_XMSDRV:
    MOV AX,4300h
    INT 2Fh
    CMP AL,80h
    JZ  CHK_XMSDRV_OK
    STC
    RET
CHK_XMSDRV_OK:
    MOV AX,4310h
    INT 2Fh
    MOV [XMS_CALL+0],BX
    MOV [XMS_CALL+2],ES
    CLC
    RET
XMS_CALL:
    DW  ?,?

XMS バージョンの取得

利用可能な機能を確認するためにバージョン情報を確認する必要がある。

パラメータ

レジスタ
AH 00h

戻り値

レジスタ
AX XMS のバージョン
BX ドライバのリビジョンナンバ
DX 0000h: HMA が存在する
  0001h: HMA が存在しない

例えば、Version 1.23 なら AX=0123h のようになる。 リビジョンナンバは通常利用しない。

HMA の要求

HMA を利用するには A20 ラインがグローバルに有効にされている必要がある。

パラメータ

レジスタ
AH 01h
DX 常駐プログラムやデバイスドライバの場合: 必要な容量 [kBytes]
  アプリケーションプログラムの場合: 0FFFFh

戻り値

レジスタ
AX 0001h: 成功 割り当てられた
  0000h: 失敗 BL に理由を示す値がある
BL (失敗時) 80h: この機能は実装されていない
  90h: HMA が存在していない
  91h: HMA はすでに利用されている
  92h: DX で指定された値は /HMAMIN= より小さい

CONFIG.SYS 内で設定される値 /HMAMIN= (HMA 利用最小サイズ) により BL=92h は発生する

HMA の解放

パラメータ

レジスタ
AH 02h

戻り値

レジスタ
AX 0001h: 成功 解放した
  0000h: 失敗 BL に理由を示す値がある
BL (失敗時) 80h: この機能は実装されていない
  90h: HMA が存在していない
  93h: HMA は割り当てられていない

A20 ラインのグローバルな有効化

パラメータ

レジスタ
AH 03h

戻り値

レジスタ
AX 0001h: 成功
  0000h: 失敗 BL に理由を示す値がある
BL (失敗時) 80h: この機能は実装されていない
  82h: A20 のエラー

A20 ラインのグローバルな無効化

パラメータ

レジスタ
AH 04h

戻り値

レジスタ
AX 0001h: 成功
  0000h: 失敗 BL に理由を示す値がある
BL (失敗時) 80h: この機能は実装されていない
  82h: A20 のエラー
  94h: A20 が有効化されていない

A20 ラインのローカルな有効化

パラメータ

レジスタ
AH 05h

戻り値

レジスタ
AX 0001h: 成功
  0000h: 失敗 BL に理由を示す値がある
BL (失敗時) 80h: この機能は実装されていない
  82h: A20 のエラー

A20 ラインのローカルな無効化

パラメータ

レジスタ
AH 06h

戻り値

レジスタ
AX 0001h: 成功
  0000h: 失敗 BL に理由を示す値がある
BL (失敗時) 80h: この機能は実装されていない
  82h: A20 のエラー
  94h: A20 が有効化されていない

A20 ラインの状態を取得

パラメータ

レジスタ
AH 07h

戻り値

レジスタ
AX 0000h: 無効
  0001h: 有効
BL 00h: 成功
  80h: この機能は実装されていない

EMB の空き容量を取得

パラメータ

レジスタ
AH 08h

戻り値

レジスタ
AX 最大連続空き容量
DX 合計空き容量
BL (AX=DX=0 のとき) 80h: この機能は実装されていない
  0A0h: EMB の空き容量はない

EMB の割り当て

EMB を利用するには A20 ラインがローカルに有効にされている必要がある。

パラメータ

レジスタ
AH 09h
DX サイズ (kBytes)

戻り値

レジスタ
AX 0001h: 成功
  0000h: 失敗 BL に理由を示す値がある
DX ハンドル (失敗時は 0000h)
BL (失敗時) 80h: この機能は実装されていない
  0A0h: EMB の空き容量はない
  0A1h: ハンドル数が足りない

EMB の解放

パラメータ

レジスタ
AH 0Ah
DX ハンドル

戻り値

レジスタ
AX 0001h: 成功
  0000h: 失敗 BL に理由を示す値がある
DX ハンドル (失敗時は 0000h)
BL (失敗時) 80h: この機能は実装されていない
  0A2h: ハンドルは無効
  0A3h: EMB がロックされている

EMB のコピー

パラメータ

レジスタ
AH 0Bh
DS:SI コピーパラメータを格納しているアドレス

コピーパラメータ

名前データサイズ内容
LengthDWORDコピーするバイト数
SourceHandleWORDコピー元ハンドル
SourceOffsetDWORDコピー元オフセット
DestHandleWORDコピー先ハンドル
DestOffsetDWORDコピー先オフセット

戻り値

レジスタ
AH 0001h: 成功
  0000h: 失敗 BL に理由を示す値がある
BL (失敗時) 80h: この機能は実装されていない
  82h: A20 のエラー
  0A3h: SourceHandle が無効
  0A4h: SourceOffset が無効
  0A5h: DestHandle が無効
  0A6h: DestOffset が無効
  0A7h: Length が無効
  0A8h: 無効な重複部分がある
  0A9h: パリティエラー

偶数番地→偶数番地 (偶数バイト) だと高速に処理されるかもしれない。 x386 以降では四倍数番地→四倍数番地だと高速に処理されるかもしれない。

下位から上位に向かってコピーされる。 コピー元とコピー先が重複する領域にある場合は注意。

コンベンショナルメモリのハンドル番号は 0000h である。

EMB のロック

パラメータ

レジスタ
AH 0Ch
DX ハンドル

戻り値

レジスタ
AX 0001h: 成功
  0000h: 失敗 BL に理由を示す値がある
DX:BX ロックされた EMB の絶対アドレス
BL (失敗時) 80h: この機能は実装されていない
  0A2h: ハンドルは無効
  0ACh: ロックされている EMB が多すぎる
  0ADh: その他の理由でロックできない

ロックできる EMB の数には限りがあるのでロックは最小限に抑え、早めに解除する。

EMB のアンロック

パラメータ

レジスタ
AH 0Dh
DX ハンドル

戻り値

レジスタ
AX 0001h: 成功
  0000h: 失敗 BL に理由を示す値がある
BL (失敗時) 80h: この機能は実装されていない
  0A2h: ハンドルは無効
  0AAh: EMB はロックされていない

EMB の情報取得

パラメータ

レジスタ
AH 0Eh
DX ハンドル

戻り値

レジスタ
AX 0001h: 成功
  0000h: 失敗 BL に理由を示す値がある
BL (成功時) EMB のロックカウント
BH EMB の空きハンドル数
DX 指定 EMB のサイズ (kBytes)
BL (失敗時) 80h: この機能は実装されていない
  0A2h: ハンドルは無効

EMB の再割り当て

パラメータ

レジスタ
AH 0Fh
BX 新しいサイズ (kBytes)
DX ハンドル

戻り値

レジスタ
AX 0001h: 成功
  0000h: 失敗 BL に理由を示す値がある
BL (失敗時) 80h: この機能は実装されていない
  0A1h: ハンドル数が足りない
  0A2h: ハンドルは無効
  0ABh: EMB はロックされている

再割り当て時に一時的にハンドルを確保するので余裕が必要。 容量を減らした場合は上位の情報が切り捨てられる。

UMB の割り当て

パラメータ

レジスタ
AH 10h
DX サイズ (×16 Bytes)

戻り値

レジスタ
AX 0001h: 成功
  0000h: 失敗 BL に理由を示す値がある
BX (成功時) 割り当てられたセグメントアドレス
DX 割り当てられた UMB のサイズ (×16 Bytes)
BL (失敗時) 80h: この機能は実装されていない
  0B0h: UMB の空き容量はない
  0B1h: 利用可能な UMB がない
DX 利用可能な UMB の最大サイズ (×16 Bytes)

INT 21h のファンクションコールと混在利用しないこと。

利用可能な最大 UMB サイズは DX=0FFFFh を指定して失敗することで求められる。

UMB の解放

レジスタ
AH 11h
DX 解放したい UMB のセグメントアドレス

戻り値

レジスタ
AX 0001h: 成功
  0000h: 失敗 BL に理由を示す値がある
BL (失敗時) 80h: この機能は実装されていない
  0B2h: セグメントアドレスは無効

参考