gate A20

A20とはなにか?

以前、8086や80186 CPUが栄えていた頃は、メモリのアクセス上限は1MBでした。これは16進数に直すと0xFFFFFであり、20本のアドレスバス(A00-A19)で表す事ができます。

やがて80286が開発され、メモリのアクセス上限は16MB(0xFFFFFF)となり、アドレスバスも24本(A00-A23)に拡張されました。しかし、メモリアクセスの時8086と80286では互換性がなくなり、8086上で動作していたプログラムが80286上で動かない事が発生します。

例えば、次のようなコードは8086と80286では、結果が異なってしまいます。

    1: movw   $0xffff,%ds    /* データセグメントに0xFFFFを代入 */
    2: movw   $0x000f,%bx    /* bx registerに0x000fを代入 */
    3: move   $0x1111,(%bx)  /* [0xFFFF]:[0x000F] = 0x1111 */
    4: incw   $bx            /* bxをインクリメント  bx = 0x0010 */
    5: move   $0x2222,(%bx)  /* [0xFFFF]:[0x0010] = 0x2222 */
                             /* 80286の場合は 0x100000 = 0x2222 */
                             /* 8086の場合は  0x00000 = 0x2222 */

    6: movw   $0x0000,%ds    /* データセグメントに0x0000を代入 */
    7: movw   $0x0000,%bx    /* bx registerに0x0000を代入 */
    8: move   (%bx),$ax      /* ax = [0x0000]:[0x0000]  */	

上記ソースの3行目では、メモリーの0xFFFFF番地に0x1111を書込んでいます。これは8086/80286 CPU共に同じ動作になります。

しかし、の5行目では8086と80286では、結果が異なってきます。[0xFFFF]:[0x0010]のリニアアドレスは0x100000となりますが、8086 CPUはアドレスバスが20本しか無い為、0x100000はオーバーフローしてしまい0x00000となり、メモリの0番地目に0x2222が書込まれます。

一方、80286 CPUはアドレスバスを24本持っていますので、オーバーフローせずメモリの0x100000番地に0x2222が書込まれます。

8086と80286の違い
8086と80286の違い

この為に、8行目の結果は、「8086 CPUの場合ax=0x2222」「80286 CPUの場合ax=不定」となり、8086 CPUで動いていたプログラムが80286 CPUでは動かない事が起こり、互換性の点で問題が出てきてしまいます。

上記の互換性を保つため、80286以降のマザーボードにはA20マスク回路を追加しました。この回路が有効になっているとA20の信号を常に0に書き換える働きをします。つまり0x100000-0x1FFFFFまでの範囲は、0x00000-0xFFFFFに変換される事になります。

A20を解除するには

A20マスク回路は、CPU側から制御可能で、現在ではいくつかの方法があります。

キーボードコントローラから制御する。
A20マスク回路が導入された当時、この回路の制御線はキーボードコントローラに接続されていました。A20マスクとキーボード、密接な関係があるのかと言うと「全然関係は無い」のですが、その当時キーボードコントローラに空きポートがあったので、そこに付けたそうです。
System Control Port から制御する。
I/O Port上の0x92番地にある,system control portのbit1に値を書込む事により制御します。
Bit 1 (rw): 0: disable A20, 1: enable A20.
BIOS から制御する。
INT 15を使い制御する。
INT 15 AX=2400 disable A20
INT 15 AX=2401 enable A20
INT 15 AX=2402 query status A20
INT 15 AX=2403 query A20 support (kbd or port 92)

OpenBSDでは、次の順で制御を試みます。

  1. System Control Port
  2. キーボードコントローラ

gateA20on関数

gateA20on関数はGate A20を有効にする関数ですが、実体はgateA20関数に引数を入れて呼んでいるだけです。

gateA20関数

System Control Portを使ってA20マスクを制御
System Control Portが有効またはキーボードコントローラが無効の場合、 System Control Portを使ってA20マスクを制御する。
キーボードコントローラを使ってA20マスクを解除
キーボードコントローラのコマンドレジスタにA20を有効にするには0xdf、A20を無効にするには0xdd(ソースでは0xcdとなっているが、たぶんバグ)を書き込む。

参考文献

A20 - a pain from the past
Last modified: Wed Jan 16 19:16:50 2008 JST