割り込みハンドラーから戻る前に、特定の例外によってスタックにプッシュされたエラー コードをポップする必要がありますか?

StackOverflow https://stackoverflow.com/questions/491613

質問

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の割り込みをマスキングこれらのダブルフォールトそっくりのタイマ割り込みを沈黙ます。

あなたのコードは、最初のタイマ割り込みを認めていなかったので

(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.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top