割り込みハンドラーから戻る前に、特定の例外によってスタックにプッシュされたエラー コードをポップする必要がありますか?
-
20-08-2019 - |
質問
256 個のエントリを含む idt テーブルをロードしました。これらはすべて同様のハンドラーを指しています。
- 例外 8 および 10 ~ 14 の場合は、例外番号をプッシュします (これらの例外はエラー コードを自動的にプッシュします)。
- 他の場合は、「ダミー」エラー コードと例外番号をプッシュします。
- 次に、共通ハンドラーにジャンプします
そのため、共通ハンドラーが開始されると、スタックは適切に配置され、例外/割り込み番号、エラー コード (単なるダミーである可能性があります)、eflags、cs、および eip が含まれます。
私の質問は、割り込みハンドラーから戻ることに関するものです。私が使う iret
スタックから例外番号とエラーコードを取り出した後に戻りますが、これは例外番号 8 では機能しません。エラーコードをスタックに残しておけば、正常に戻ります。
質問:
- エラーコードをスタックに置く例外のために、スタック上にエラーコードを残しておかなければなりませんか?もしそうなら、どうやって
iret
エラーコードをポップする必要があるかどうかを決定しますか? - 割り込みを有効にするとすぐに例外 8 (二重障害) が発生しますが、その後はすべて正常に動作します (趣味の OS を開発しています)。これは正常な動作ですか、それともどこかにバグがあるのでしょうか?
解決
CPU が自動的にエラー コードをプッシュした場合、ハンドラーは しなければならない の前にポップしてください iret
. 。の iret
命令は、それが障害なのか、トラップなのか、外部割り込みなのか、どこから来たのかを知りません。常に同じことを行い、スタックにエラー コードがないことを前提とします。
SDM (ソフトウェア開発者マニュアル)、第 3 巻、第 5 章、セクション 5.13 の「エラー コード」から引用:
エラーコードは、ダブルワードまたは単語としてスタックでプッシュされます(デフォルトの割り込み、トラップ、またはタスクゲートのサイズに応じて)。ダブルワードプッシュのためにスタックをアラインしたままにするために、エラーコードの上半分が予約されています。IRET命令が実行されて例外ハンドラーから戻るときにエラーコードがポップされないため、ハンドラーは返品を実行する前にエラーコードを削除する必要があることに注意してください。
見つけることができます IA-32 ソフトウェア開発者マニュアル ここ: http://www.intel.com/products/processor/manuals/
第 3 巻パート 1、第 5 章では、例外と割り込みの処理について説明します。ボリューム 2 パート 1 には、 iret
命令。
他のヒント
私は小型のx86 OSが戻ってしばらくを書きました。ファイル ISRを見てみましょう。 CVSリポジトリ内のasm でます。
私たちはハンドラを設定する方法は、ほとんどが自動的にプッシュされたエラーコードを取得し、いくつかのハンドラを考慮するために、スタックにダミーDWORDを押して注意してください。我々はIRETを経由して戻ったとき、我々は常にかかわらず、割り込みのスタック上の2つのダブルワードを取ることができるし、うまく物事をクリーンアップするIRET前に、ESP 8を追加を行います。
それはあなたの最初の質問に答える必要があります。
あなたの2番目の質問については:あなたはそれを正しく設定していない場合は、割り込みを有効にダブルフォールトは、...うーんページングに問題がある可能性があります。あまりにも百万他の事をすることができます。)
私はすぐに私は割り込みを有効にして「ダブルフォールト」と同様の問題がありました。まあ、彼らはダブルフォルトのようにの見えたが、彼らは本当にタイマ割り込みました!
をダブルフォールトは、割り込み番号8
されます。
残念ながら、デフォルトのPIC設定信号タイマー割り込み番号として割り込み(DEFAULT_PIC_BASE + TIMER_OFFSET)
= (8 + 0)
= 8
ます。
すべての私のPICの割り込みをマスキングこれらのダブルフォールトそっくりのタイマ割り込みを沈黙ます。
あなたのコードは、最初のタイマ割り込みを認めていなかったので(PICのは。彼らは次の1を生産する前に割り込みを確認するためにCPUを必要とし、PICは、あなたに多くを与えたことはない!あなたが唯一の1つを得た理由ではなく無数のものよりも、です期待しているかもしれません。)
エラーコードをスタックに置く例外のために、エラーコードをスタック上に残す必要がありますか?
他の人が述べたように、次のいずれかを行う必要があります。
pop %eax
/* Do something with %eax */
iret
または、エラー コードを無視したい場合は、次のようにします。
add $4, %esp
iret
そうしないと、 iret
はエラー コードを新しい CS として解釈し、次のような一般的な保護違反が発生する可能性があります。 ページ フォールト ハンドラーからの iret が割り込み 13 (一般保護フォールト) とエラー コード 0x18 を生成するのはなぜですか?
このページハンドラーの最小限の動作 これを説明するために私が作成したものです。コメントアウトしてみてください pop
そしてそれが爆発するのを見てください。
上記を比較してください 除算エラー例外 これはスタックをポップしません。
単純に実行する場合は、 int $14
, 、余分なバイトはプッシュされません。これは実際の例外でのみ発生します。
インテル マニュアル第 3 巻システム プログラミング ガイド - 325384-056US 2015 年 9 月 表6-1。「保護モードの例外と割り込み」列の「エラー コード」には、エラー コードをプッシュするかどうかを示す割り込みのリストが含まれます。
38.9.2.2「ページフォールトのエラーコード」でエラーの意味が説明されています。
これに対処する適切な方法は、ダミーのエラー コードをプッシュすることです。 0
状況を均一にするために、これを行わない割り込みをスタックに追加します。ジェームズ・モロイのチュートリアル まさにそれをやります.
Linux カーネル 4.2 も同様のことを行うようです。下 アーチ/x86/エントリ/エントリ64.S 割り込みをモデル化します has_error_code
:
trace_idtentry page_fault do_page_fault has_error_code=1
そしてそれを同じファイルで次のように使用します。
.ifeq \has_error_code
pushq $-1 /* ORIG_RAX: no syscall to restart */
.endif
プッシュを行うのは次の場合です has_error_code=0
.