14

ユーザー モード (特権レベル 3) でいくつかのコードを実行する小さな OS を作成しています。そのユーザー レベルのコードから、メッセージを出力する OS に割り込みを呼び出したいと思います。今のところ、割り込みハンドラーがどのように引数を受け取るかなどはあまり気にしません。コードが実行されたことを割り込みハンドラーが私 (ユーザー) に通知するようにしたいだけです。

私の質問は: ユーザー モードでコードを実行するにはどうすればよいですか? コード セグメントとデータ セグメント (両方ともユーザー モード権限を持つ) を使用してローカル記述子テーブルをセットアップする機能があります。私が理解していないのは、これらのセグメントをcsss、およびにロードする方法ですds。LDT を正常にロードしましたが、実際の使用方法がわかりません。を使うべきだと聞いたことがありますiretが、正確な方法がわかりません。

もう 1 つの質問は、割り込みハンドラーがどのように機能するかということです。ベクタ番号 0x40 の割り込みハンドラをインストールして、"hello, user mode!" と出力したいとします。割り込みハンドラーのセットアップ方法は知っていますが、ユーザー モードからカーネル割り込みハンドラーに入ったときにコンテキストがどのように切り替わるのか正確にはわかりません。csルーチンは IDT エントリで指定されたコード セグメントから実行されるため、レジスタを変更する必要があることはわかっています。スタックセレクターもおそらく変更されることも理解していますが、これについては確信が持てません。

割り込みゲートが呼び出されたときにどのようなコンテキスト変更が行われるかを誰かに説明してもらえますか?

4

2 に答える 2

29

リング 3 へのアクセスiretは、動作方法が文書化されているため、 を使用して行うことができます。割り込みを受け取ると、プロセッサは以下をプッシュします。

  1. スタック セグメントとポインタ (ss:esp)、4 ワード
  2. EFLAGS
  3. 戻りコード セグメントと命令ポインタ (cs:eip)、4 ワード
  4. 必要に応じて、エラー コード。

iret手順 1 ~ 3 を元に戻すことで機能します (ISR は、必要に応じて手順 4 を元に戻す責任があります)。この事実を利用して、必要な情報をスタックにプッシュし、iret命令を発行することで、リング 3 に到達できます。コードとスタック セグメントに適切な CPL があることを確認してください (下位 2 ビットはそれぞれに設定する必要があります)。ただし、iretデータ セグメントは変更されないため、手動で変更する必要があります。これを行うには命令を使用しmovますが、これを実行してからリングを切り替えるまでの間、スタック外のデータを読み取ることはできません。

cli
mov   ax, Ring3_DS
mov   ds, eax
push  dword Ring3_SS
push  dword Ring3_ESP
pushfd
or    dword [esp], 0x200 // Set IF in EFLAGS so that interrupts will be reenabled in user mode
push  dword Ring3_CS
push  dword Ring3_EIP
iret

完全で実用的な例が必要な場合は、このチュートリアルを参照してください。


割り込みが発行されると、プロセッサは IDT を読み取り、ISR の適切なコード セグメントと命令ポインタを取得します。次に、TSS を調べて、新しいスタック セグメントとポインターを見つけます。適切に変更ssesp、古い値を新しいスタックにプッシュします。データ セグメント レジスタは変更されません。ISR のメモリにアクセスする必要がある場合は、これを手動で行う必要があります。

于 2011-07-31T23:08:32.117 に答える
1

retf を実行することもできます。特権の少ないコード セグメントに戻ると、新しい ss と sp が特権スタックから取り出されます。

far 呼び出しに対して far return を実行し、割り込みに対して irets を実行していることを確認してください。それらの唯一の違いは、スタックにフラグが存在することですが、それらを混同しないことが賢明です。

また、例外によってエラー コードがスタックにプッシュされる場合があることも忘れないでください。

于 2015-03-24T03:46:21.210 に答える