Operating Systems Development Series
Enabling A20
by Mike, 2008, 2009

はじめに

ようこそ!:)

前回のチュートリアルでは、プロセッサを 32 ビットモードに切り替える方法を説明しました。 また、最大 4 GB のメモリにアクセスする方法を学びました。これは素晴らしいことですが、どうやって

また、PCはリアルモードで起動しますが、このモードでは16ビットレジスタ、つまり16ビットセグメントアドレッシングという制約があることも覚えておいてください。このため、まだ1GBのメモリにさえアクセスできない。1MBの壁さえも越えられない。どうすればいいのか?20番目のアドレスラインを有効にする必要があります。これには直接ハードウェアプログラミングが必要なので、それについても説明します。

というわけで、メニューはこんな感じです。

  • ダイレクトハードウェアプログラミング - 理論編
  • ダイレクトハードウェアプログラミングとコントローラー
  • キーボードコントローラプログラミング - 基礎編
  • A20の有効化

C言語などの高級言語を使用する場合、1MB以上のメモリにアクセスできることが重要なポイントになります。このため、A20 (アドレスライン20) を有効にすることが重要です!

注意:まだ1MB以上のメモリにアクセスできないことを忘れないでください。トリプルフォールトの原因となります。

また、このチュートリアルでは、ハードウェアの直接プログラミングを行うため、これまでのチュートリアルより少し複雑になります。心配しないでください - この後、カーネル用のデバイスドライバを開発するときに、直接ハードウェアプログラミングをより経験することができます。

準備はいいですか?

準備完了

ここまでお付き合いいただいた方々は、OS開発がいかに大変なものであるかをご存知だと思います。しかし、私たちはまだ難しいことに手をつけていません。ここで紹介するのは、まだ基本的でありながら、かなり高度な概念ばかりです。しかし。これからもっともっと難しくなっていくのです。

すべてのコントローラは、正しく動作するために特別な方法でプログラムされる必要があります。例えば、ハードディスクを書き込む(または読む)には、まずそれがIDEかSCSIかを判断する必要があります。そして、IDEとSCSIの接続を制御するIDEコントローラまたはSCSIコントローラを使用して、ドライブ番号を決定し、プログラムを作成しなければなりません。この2つのコントローラはそれぞれ異なるものです。

さらに複雑なことに、「セクタ」は512バイトとは限りません。従って、「セクタの読み書き」は曖昧です。

次に、メモリ管理とフラグメンテーションがあります。ここで、ページング仮想アドレス空間メモリ管理ユニット(MMU)が登場します。

ドライブの読み書きは、他のドライブとは全く異なります。典型的なフォーマットとファイルシステムはメディアによって異なるので、FAT12フロッピーから起動するコードは、CDFSファイルシステムのCD ROMを起動するためには動作しません。ハードウェア固有のコード(と低レベルのコード)を抽象化することで、ほとんどのコードをこれらのデバイスで動作させることができます。

ハードディスクにファイルを書き込む」と言うとき、通常、「ファイル」とは何かを定義したくはないでしょう。これが、抽象化が非常に重要な理由です。

ここにあるものはすべて保護モード(つまり32ビットコード)用のものですが、リアルモードでも同様に動作します。このため、プロテクテッドモードのルールを覚えておいてください。

  • 割り込みは禁止!割り込みの使用はトリプルフォールトを引き起こします。
...ですから、あなたは完全に自分自身の力でやっているのです。

カーネルデバッグ

デバッグは芸術です。デバッグは芸術であり、問題を捕捉し、深刻な事態になる前にソフトウェアのエラーを修正する方法を提供するものです。カーネルデバッグは、カーネルレベルのリング0プログラムのデバッグに関係します。 これは決して簡単な作業ではありません。

高レベル言語におけるデバッガ

CやC++のような言語のデバッガは、実行時に変数名やルーチン名、その値や場所などを表示する方法を提供しています。しかし、問題は私たちのプログラムには、まだシンボリックネームがありません。まだバイナリレベルで動いているのです。

ダイレクトハードウェアプログラミング - 理論編

オペレーティングシステムの開発では、ここからが大変なのです。

「ハードウェアの直接プログラミング」とは、個々のチップと直接通信する(制御する)ことを指します。これらのチップが(何らかの方法で)プログラム可能である限り、我々はそれらを制御することができます。

チュートリアル7では、システムがどのように動作するかを非常に詳細に見てきました。 また、ソフトウェアポートがどのように動作するか、ポートマッピング、IN命令とOUT命令について話し、x86アーキテクチャにおける一般的なポートマッピングの大きな表も示しました。

プロセッサがIN命令やOUT命令を受け取ると、コントロールバスの I/Oアクセスラインが有効になることを覚えておいてください。システムバスはメモリコントローラと I/Oコントローラの両方に接続されているため、両コントローラはコントロールバスの特定のアドレスとアクティブなラインを聞き取る。I/Oアクセスラインがセットされていれば(電気が通っている、つまりアクティブ(1))、I/Oコントローラはそのアドレスを取得する。

I/Oコントローラは、次に他のすべてのデバイスにポートアドレスを与え、コントローラチップからの信号を待ちます(それが何らかのデバイスに属していることを意味します - だから、そのデバイスにどんなデータでも与えます)。もし、コントローラチップからの応答がなく、ポートアドレスがセットバックされると、それは無視される。

これがポートマッピングの仕組みです。(詳しくはチュートリアル7を参照してください)。

また、1つのコントローラチップに複数のポートアドレスを割り当てることができることも覚えておいてください。 ポートアドレスは、BIOSがロードされ実行される前でも、BIOS POSTによって割り当てられます。 なぜでしょうか?多くのデバイスは、さまざまな種類の情報を必要とします。あるポートは「レジスタ」を表し、他のポートは「データ」または「レディ」を表すかもしれません。醜いことです、わかっています。しかし、もっと悪いことがあります。システムによって、ポートアドレスが大きく異なることがあるのです。x86アーキテクチャはバックワード互換なので、基本的なデバイス(キーボードやマウスなど)は通常、常に同じアドレスになります。しかし、より複雑なデバイスはそうではないかもしれません。

ハードウェアの直接プログラミングとコントローラ

すべてがどのように動くかをよりよく理解するために、コントローラについて見てみましょう。結局のところ、私たちは、特にプロテクトモードにおいて、コントローラと頻繁に会話することになるのです。

多くのPCは、初期のインテル8042マイクロコントローラ・チップをベースにしています。このコントローラチップは、IC(Intergrated Circuit)チップとして組み込まれているか、マザーボードに直接組み込まれています。これは通常、サウスブリッジに配置されています。

このマイクロコントローラーは、キーボードに接続されたコードを通じて、キーボード内の別のマイクロコントローラーチップと通信を行います。

キーボードのキーを押すと、キーの下にあるラバードームが押されます。 ラバードームの下側には導電性の接点があり、押されるとキーボード回路の2つの導電性の接点と接触します。このため、電流を流すことができる。各キーは1対の電気線で接続されています。それぞれの信号が変化すると(天候によってキーが押される)、(一連のラインから)メイクコードが生成されます。このメイクコードがキーボード内部のマイコンチップに送られ、コンピュータのハードウェアポートに接続するコードを通じて送られます。これは、オンとオフの電気プッシュのシリーズとして送信されます。クロックサイクルに応じて、各パルスはビットパターンを表す一連のビットに変換することができます。

私たちはマザーボードの上にいます。この一連のビットは、電気信号としてサウスブリッジを通り、8042マイクロコントローラにまで届きます。このマイコンは、メイクコードをスキャンコードにデコードし、内部のレジスタに格納します。つまり、バッファです。内部レジスタはEEPROMチップなどでもよいので、好きなときに電気的にデータを上書きすることができる。

起動時にBIOSのPOSTが各デバイス(I/Oコントローラを通して)にポートアドレスを割り当てる。これは、デバイスを照会することによって行われる。つまり、ポート0x60を参照すると、この内部レジスタからの読み出しを要求していることになります。

ポートマッピングやIN/OUT命令については、あとはご存知の通りですので、このレジスタから読み出してみましょう。

in al, 0x60 ; get byte from 8042 microcontroller input register
おそらく推測できるように、8042マイクロコントローラはキーボードコントローラです。このチップの様々なレジスタと通信することで、キーボードからの入力を読んだり、スキャンコードをマップしたり、他にもいろいろなことができます。A20を有効にするように。

A20を有効にするために、なぜキーボードコントローラと通信しなければならないのか不思議に思われるかもしれません。これについては、次に説明します。

ゲートA20 - 理論編

最後に、A20について説明します。このチュートリアルのほとんどは、A20とは直接関係のない他のトピックを扱っています。しかし、A20を有効にするには、マイクロコントローラのプログラミングと一緒に、ハードウェアの直接プログラミングの基礎から始めたいと思いました。

A20ラインを有効にするには、キーボードマイクロコントローラをプログラミングする必要があるかもしれません。このため、キーボードコントローラのプログラミングについて少し取り上げますが、キーボードのプログラミングにはまだ踏み込みません。

ちょっとした歴史

IBMがIBM PC ATマシンを設計したとき、新しいIntel 80286マイクロプロセッサを使用しましたが、これはリアルモードでは以前のx86マイクロプロセッサと完全に互換性があるわけではありませんでした。問題点は?古いx86プロセッサには、アドレス線A20〜A31がない。そのサイズのアドレスバスをまだ持っていなかったのだ。そのため、最初の1MBを超えると、プログラムが折り返して表示されてしまうのだ。80286のアドレス空間では、32本のアドレス線が必要だったのだ。しかし、32本すべてがアクセス可能だと、また折り返しの問題が出てくる。

この問題を解決するために、Intelはプロセッサとシステムバスの間の20番目のアドレスラインにロジックゲートを設置した。 このロジックゲートは、有効にも無効にもできることから、Gate A20と名付けられた。古いプログラムではラップラウンドに依存するため無効化され、新しいプログラムでは有効化される。

起動時、BIOSはメモリのカウントとテスト時にA20を有効にし、OSに制御を委ねる前に再び無効にする。

A20を有効にする方法はたくさんあります。A20ゲートを有効にすると、アドレスバスの32本のラインすべてにアクセスできるようになり、32ビットアドレス、つまり最大0xFFFFFFF(4GB)のメモリを参照できるようになる。

A20ゲートは、もともと8042マイコン(キーボード・コントローラ)のP21ラインに接続されていた電子ORゲートである。このゲートは、出力ポート・データのBit 1として扱われる出力ラインである。このデータを受信するコマンドを送ったり、データを変更することも可能です。このビットをセットして、出力線のデータを書き込めば、マイコンがORゲートをセットして、A20線を有効にすることができます。この方法は、自分で直接行うことも、間接的に行うこともできます。詳しくは次のセクションで説明します。

起動時に、BIOSはA20ラインを有効にして、メモリをテストします。メモリテストの後、BIOSは古いプロセッサとの互換性を維持するためにA20ラインを無効にします。このため、デフォルトでは、オペレーティングシステムでは、A20 ラインは無効になっています。

マザーボードの構成によって、A20 ゲートを再び有効にする方法がいくつかあります。このため、ここでは、A20を有効にするための一般的な方法をいくつか取り上げます。

次は、この方法について見てみましょう。

ゲートA20の有効化

A20を有効にするには、さまざまな方法があることを覚えておいてください。携帯性を重視するのであれば、複数の方法を併用する必要があるかもしれません。

方法1:システム制御ポートA

これは、A20アドレスラインを有効にするための非常に高速な方法ですが、移植性が低いです。

MCAやEISAを含むいくつかのシステムでは、システム制御ポートI/O 0x92からA20を制御することができます。ポート0x92の正確な詳細と機能は、メーカーにより大きく異なります。しかし、一般的に使用されるビットがいくつかある。

  • ビット0- 1に設定すると、高速リセットが発生する(リアルモードに戻るために使用)
  • ビット1- 0: A20を無効化、1: A20を有効化
  • ビット2- メーカー定義
  • ビット3- パワーオンパスワードバイト(CMOSバイト0x38-0x3fまたは0x36-0x3f)。0: アクセス可能, 1: アクセス不可
  • ビット4-5- 製造元定義
  • ビット6-7- 00: HDDアクティビティLEDオフ、その他の値は "オン"
この方法を用いてA20を有効にする例を示します。
mov al, 2 ; set bit 2 (enable a20) out 0x92, al
このポートでできることは他にもたくさんあることに注意してください。
mov al, 1 ; set bit 1 (fast reset) out 0x92, al

警告!

この方法は簡単な方法の1つですが、他のハードウェアデバイスと衝突するのを見たことがあります。通常、システムが停止してしまうでしょう。もしこの方法を使いたいのであれば(そしてそれがうまくいくのであれば)、私はこの方法を使うことにこだわりますが、この点には留意してください。

その他のポート...

システムによっては、他のI/Oポートを使用してA20を有効または無効にすることができることを述べておく必要があると思います。

最も一般的なのは、I/Oポート0xEEです。これらのシステムでI/Oポート0xEE(「FAST A20 GATE」)を有効にすると、このポートから読み出すとA20が有効になり、書き込むとA20が無効になる。ポート0xEF(「FAST CPU RESET」)も、システムをリセットするために同様の効果があります。

他のシステムでは、異なるポートを使用するかもしれません(例えば、AT&T 6300+では、A20を有効にするにはI/Oポート0x3f20に0x90を書き込み、A20を無効にするには0を書き込むことが必要です)。また、I/Oポート0x65のビット2やI/Oポート0x1f8のビット0を使ってA20を有効/無効にするシステムも存在するという噂もある(0:無効、1:有効)。

このように、A20を使用する場合、多くの問題があります。確実な方法は、マザーボードメーカーに問い合わせることです。

方法2:Bios

多くのBiosは、A20の有効化と無効化のための割り込みを可能にしています。

INT 0x15 関数 2400 - A20を無効にする

この機能は、A20のゲートを無効にするものです。使い方はとても簡単です。
mov ax, 0x2400 int 0x15
以下を返します。

CF = 成功すればクリア
AH = 0
CF = エラー時に設定
AH = ステータス (01=キーボードコントローラがセキュアモード、0x86=機能がサポートされていない)

INT 0x15 ファンクション 2401 - A20を有効にする

この関数は、A20 ゲートを有効にする。
mov ax, 0x2401 int 0x15
戻り値。

成功した場合、CF = クリア
AH = 0
CF = エラーの場合、設定される
AH = ステータス (01=キーボードコントローラがセキュアモード、0x86=機能がサポートされていない)

INT 0x15 ファンクション 2402 - A20の状態

この関数は、A20 ゲートの現在のステータスを返す。
mov ax, 0x2402 int 0x15
を返す。

CF = 成功すればクリア
AH = ステータス (01:キーボードコントローラはセキュアモード、0x86:機能はサポートされていません)
AL = 現在の状態 (00: 無効、01: 有効)
CX = 0xc000の読み取りでキーボードコントローラがレディでない場合、0xffffに設定される。
CF = エラー時に設定

INT 0x15 ファンクション 2403 - A20のサポート状況を問い合わせる

この関数は、A20のサポートについてシステムに問い合わせるために使用される。
mov ax, 0x2403 int 0x15
戻り値

CF = 成功すればクリア
AH = ステータス (01: キーボードコントローラはセキュアモード、0x86: 機能がサポートされていない)
BX = ステータス。

BX にはビットパターンが含まれます。

  • キーボードコントローラでサポートされている場合、ビット0- 1
  • ビット1- I/Oポート0x92のビット1でサポートされている場合は1
  • ビット2-14- 予約
  • ビット15- 追加データがある場合1

方法3:キーボード・コントローラ

これはおそらく、A20を有効にする最も一般的な方法です。非常に簡単ですが、キーボードマイクロコントローラのプログラミングの知識が必要です。この方法は、最も移植性が高いと思われるので、私が使用することになります。この方法は、キーボードマイコンのプログラミングの知識が必要なので、まず、そのことについて少し見ておく必要があります。

これは、私が最初にハードウェアプログラミングをカバーしたいと思った理由でもあります。ハードウェアの直接プログラミングとはどういうものか、初めて垣間見ることができるのです。心配しないでください、そんなに悪いことではありませんよ。でも、時にはとても複雑になることもあります。)

8043キーボードコントローラ - ポートマッピング

このコントローラと通信するためには、コントローラがどのI/Oポートを使っているかを知っておく必要があります。

このコントローラのポートマッピングは以下の通りです。

Port Mapping
Port Read/Write Descripton
0x60 Read Read Input Buffer
0x60 Write Write Output Buffer
0x64 Read Read Status Register
0x64 Write Send Command to controller

I/Oポート0x64にコマンドバイトを書き込むことによって、このコントローラにコマンドを送信します。コマンドがパラメータを受け取る場合、このパラメータはポート0x60に送信されます。 同様に、コマンドによって返された結果は、ポート0x60から読み取ることができる。

キーボードコントローラ自体は非常に低速であることに注意する必要があります。私たちのコードはキーボードコントローラより速く実行されるので、先に進む前にコントローラの準備ができるのを待つ方法を提供しなければなりません。

これは通常、コントローラのステータスを問い合わせることで行います。もし、これが混乱するようであれば、心配しないでください、全てはすぐに明らかになります。

8043 キーボード・コントローラ・ステータス・レジスタ

では、コントローラの状態を知るにはどうしたらいいのでしょうか?上の表を見ると、I/Oポート0x64から読まなければならないことがわかります。このレジスタから読み出される値は、特定のフォーマットに従った8ビット値です。それがこちら...
  • ビット0:出力バッファ・ステータス
    • 0: 出力バッファは空です、まだ読みません。
    • 1: 出力バッファ満杯、読んでください :)
  • ビット1:入力バッファ・ステータス
    • 0: 入力バッファは空です、書き込み可能です
    • 1: 入力バッファが一杯、書き込み不可
  • ビット2:システム・フラグ
    • 0: パワーオンリセット後に設定
    • 1: キーボードコントローラーのセルフテスト(BAT)が正常に終了した後にセットされる。
  • ビット3:コマンドデータ
    • 0: 入力バッファへの最後の書き込みがデータ(ポート 0x60 経由)。
    • 1: 入力バッファへの最後の書き込みはコマンド(ポート0x64経由)。
  • ビット4:キーボードロック
    • 0: ロックされている
    • 1: ロックされていない
  • ビット5:補助出力バッファフル
    • PS/2システム
      • 0: ポート0x60からの読み出しが有効かどうかを判断 有効な場合、0=キーボード・データ
      • 1:マウスデータ、ポート0x60からの読み込みが可能な場合のみ
    • ATシステム
      • 0: OKフラグ
      • 1:キーボードコントローラからキーボードへの送信でタイムアウト。これは、キーボードが存在しないことを示す場合がある。
  • ビット6:タイムアウト
    • 0: OKフラグ
    • 1: タイムアウト
    • PS/2です。
      • 一般的なタイムアウト
    • ATです。
      • キーボードからキーボードコントローラへの送信でタイムアウト。パリティエラーの可能性あり(この場合、ビット6と7の両方が設定される)。
  • ビット7:パリティエラー
    • 0: OKフラグ、エラーなし
    • 1:最後のバイトでパリティエラー

ご覧のとおり、いろいろなことが起こっています。重要なビットは上記の太字で、コントローラの出力または入力バッファが満杯かどうかを示しています。

以下に例を示します。例えば、あるコマンドをコントローラに送るとします。このコマンドはコントローラの入力バッファに格納されます。つまり、このバッファがまだいっぱいであれば、コマンドはまだ実行されていることになります。次のようなコードになります。

wait_input: in al,0x64 ; read status register test al,2 ; test bit 2 (Input buffer status) jnz wait_input ; jump if its not 0 (not empty) to continue waiting
これは、入力バッファと出力バッファの両方に対して行う必要があります。

コントローラを待つことができるようになったので、今度は実際にコントローラに何をして欲しいかを伝えることができなければなりません。これはコマンドバイトによって行われます。それでは見てみましょう。

8043キーボード・コントローラのコマンド・レジスタ

I/Oポートの表を見ると、コントローラにコマンドを送信するために、I/Oポート0x64に書き込む必要があることがわかります。

キーボードコントローラは多くのコマンドを持っています。これはキーボードプログラミングのチュートリアルではないので、ここにすべてをリストアップすることはしません。しかし、より重要なものはリストアップします。

Keyboard Controller Commands
Keyboard Command Descripton
0x20 Read Keyboard Controller Command Byte
0x60 Write Keyboard Controller Command Byte
0xAA Self Test
0xAB Interface Test
0xAD Disable Keyboard
0xAE Enable Keyboard
0xC0 Read Input Port
0xD0 Read Output Port
0xD1 Write Output Port
0xDD Enable A20 Address Line
0xDF Disable A20 Address Line
0xE0 Read Test Inputs
0xFE System Reset
Mouse Command Descripton
0xA7 Disable Mouse Port
0xA8 Enable Mouse Port
0xA9 Test Mouse Port
0xD4 Write to mouse

繰り返しますが、これ以外にも多くのコマンドがあることに注意してください。 後で全部見ますので、心配しないでください :)

方法3.1:キーボードコントローラでA20を使用可能にする

上の表のコマンドバイト0xDDと 0xDFに注目してください。 これは、キーボードコントローラーを使用してA20を有効にする1つの方法です。
; Method 3.1: Enables A20 through keyboard controller mov al, 0xdd ; command 0xdd: enable a20 out 0x64, al ; send command to controller
すべてのキーボード・コントローラーがこの機能をサポートしているわけではありません。すべてのキーボードコントローラーがこの機能をサポートしているわけではありません。

方法3.2:出力ポートからA20を使用可能にする

A20を有効にするもう一つの方法は、キーボードコントローラの出力ポートを使うことです。 これを行うには、コマンドD0とD1を使って出力ポートを読み書きする必要があります (参考までに、キーボードコントローラのコマンド表をもう一度見てください)。

この方法は、他の方法より少し複雑ですが、それほど悪くありません。 基本的には、キーボードを無効にして、コントローラから出力ポートを読み取ります。 8042は、1つのポートを含んでいます。1つは入力、もう1つは出力です。そうだったのか...。3つ目はテスト用です。これらの「ポート」は、マイクロコントローラのハードウェア・ピンに過ぎません。

物事をシンプルにするために(そしてこれはキーボードプログラミングのチュートリアルではないので)、今は出力ポートだけを見てみましょう。

さて、出力ポートを読み出すには、次のような出力ポート読み出しコマンド(0xD0)をコントローラに送ります(参考までにキーボードコントローラコマンドの表をご覧ください)。

; read output port into al mov al,0xD0 out 0x64,al
これで、出力ポートのデータが取得できました。しかし、これではあまり意味がありません。

では、見てみましょう。

  • Bit 0: System Reset
    • 0: Reset computer
    • 1: Normal operation
  • Bit 1: A20
    • 0: Disabled
    • 1: Enabled
  • Bit 2-3: Undefined
  • Bit 4: Input buffer full
  • Bit 5: Output Buffer Empty
  • Bit 6: Keyboard Clock
    • 0: High-Z
    • 1: Pull Clock Low
  • Bit 6: Keyboard Data
    • 0: High-Z
    • 1: Pull Data Low

これらのビットのほとんどは、変更する必要はありません。ビット0を1に設定するとコンピュータがリセットされ、ビット1を設定するとゲートA20が有効になります。他のビットが触れないように、この値をORしてビットを設定する必要があります。ビットを設定した後は、その値を書き戻すだけです(コマンド・バイト 0xD1)。

出力ポートの読み取りと書き込みに使用されるコマンドは、データのためにコントローラの入力と出力バッファを使用します。

つまり、出力ポートを読み出すと、読み出されたデータはコントローラの入力バッファ・レジスタに格納されます。I/Oポートの表を見ると、I/Oポート0x60から読み込んだデータを取得することになります。

例を見てみましょう。wait_inputは入力バッファが空になるのを待ち、wait_outputは出力バッファが空になるのを待ちます。

; send read output port command mov al,0xD0 out 0x64,al call wait_output ; read input buffer and store on stack. This is the data read from the output port in al,0x60 push eax call wait_input ; send write output port command mov al,0xD1 out 0x64,al call wait_input ; pop the output port data from stack and set bit 1 (A20) to enable pop eax or al,2 // 2 = 10 binary out 0x60,al // write the data to the output port. This is done through the output buffer
それだけなんです。:)この方法は、他の方法より少し複雑ですが、最も移植性があります。

探すべき注意点

エミュレーションなので、これらのほとんどはBochsには適用されませんが、代わりに実際のハードウェアに適用されます。

コントローラが間違ったコマンドを実行した

例えば、in al,0x60の代わりにin al, 0x61を使うと、キーボードマイコンのステータスレジスタ(ポート0x60)ではなく、別のレジスタから読み込むことになります。

コントローラの未知のコマンド

ほとんどのコントローラは、知らないコマンドは無視し、そのまま破棄します(コマンドレジスタがある場合はクリアします)。

ただし、コントローラによっては誤動作することがあります。詳しくは、「誤動作」の項をご覧ください。

コントローラーの誤動作

このようなことは稀にしか起こらないが、可能性はある。2つの顕著な例はPentiumプロセッサで、悪名高いFDIVとfoofのバグがあります。FDIVバグは、CPU内部の設計上の欠陥で、プロセッサ内部のFPUが誤った結果を出すというものです。

foofの問題はよりシリーズ化されています。プロセッサにコマンドバイト0xf0 0x0f 0xc7 0xc8が与えられたとき、これはHCF(Hault and Catch Fire)命令の一例です。(これらの命令のほとんどは、プロセッサ自体をロックしてしまい、ユーザーをハードリブートさせる可能性があります。また、これらの命令の使用により、異常な副作用が発生する場合もあります。

これらの起こりうる問題については、よく考えておく必要があります。実際に起こることであり、コントローラも例外ではありません(命令バイトを個々のポートに送信することを思い出してください)。例えば、ポート0x64--キーボードコントローラのコマンドレジスタ)。

しかし、これらの不具合のほとんどは、デバイスの「設計上の欠陥」と考えるのが妥当でしょう。

ハードウェアの物理的な故障

また、稀ではあるが、ソフトウェアによってハードウェアの損傷を与えることも可能である。簡単な例としては、フロッピーディスクドライブがあります。フロッピードライブのモーターはフロッピードライブコントローラ(FDC)を通じて直接制御する必要がある。モーターを停止させるコマンドを送り忘れると、フロッピーディスクドライブが摩耗して壊れてしまうことがあります。ご注意ください。

トリプル障害

マイクロコントローラは、コントロールバスを介してプライマリプロセッサーに問題があることを知らせることがあります。この場合、プロセッサーは例外を通知し、もちろんコンピューターは再起動します。

Bochsのコントローラの問題

コントローラに問題がある場合、Bochsはトリプルフォルトを発生させ、その情報(問題)をログに記録します。

例えば、キーボードコントローラに未知のコマンド(例えば0)を送ろうとした場合。

mov al, 0x00 ; some random command out 0x64, al ; try to send command to controller
Bochsはトリプルフォルトを発生させ、その情報をログに記録します。
[KBD ] unsupported io write to keyboard port 64, value = 0
「KBD」は、キーボードコントローラデバイスによってログが書き込まれたことを表します。

まとめ

すごい、すごい。このチュートリアルは、私が当初期待したよりも大きなものです。

新しい概念をたくさん見ることができました。また、ハードウェアプログラミングの経験もできました。 覚えておいてください。プロテクトモードでのハードウェアとの通信は、この方法しかありません。 さようなら、割り込み。さようならBIOS。もう完全に自分たちでやるしかないんです。

これで、Windowsをもう少し評価できるようになるかもしれませんね。)結局のところ、彼らは皆、私たちのレベルから始めなければならなかったのです。

まだすべてを理解していなくても心配しないでください--複雑なのは分かっています。Kernelに到達したら、キーボードマイクロコントローラのプログラミングとそのドライバを書くことに特化した全体のチュートリアルを用意するつもりです。いいでしょ?

次のチュートリアルはもっと簡単です。プロテクトモードは一旦保留にして、リアルモードのコードに戻りましょう。FAT12 のロードコードを追加して、カーネルをロードします。 A20 が有効になっているので、1MB でロードできます!

また、BIOS情報を取得したり、その他、思いついたことを何でもやっていきます :)それではまた。